Instrukcje: Zmienianie dostawcy kryptograficznego dla klucza prywatnego certyfikatu X.509
W tym temacie pokazano, jak zmienić dostawcę kryptograficznego używanego do udostępniania klucza prywatnego certyfikatu X.509 oraz jak zintegrować dostawcę z platformą zabezpieczeń Windows Communication Foundation (WCF). Aby uzyskać więcej informacji na temat używania certyfikatów, zobacz Praca z certyfikatami.
Struktura zabezpieczeń WCF umożliwia wprowadzenie nowych typów tokenów zabezpieczających zgodnie z opisem w temacie Instrukcje: tworzenie tokenu niestandardowego. Istnieje również możliwość użycia tokenu niestandardowego do zastąpienia istniejących typów tokenów dostarczonych przez system.
W tym temacie udostępniony przez system token zabezpieczający X.509 jest zastępowany przez niestandardowy token X.509, który zapewnia inną implementację klucza prywatnego certyfikatu. Jest to przydatne w scenariuszach, w których rzeczywisty klucz prywatny jest udostępniany przez innego dostawcę kryptograficznego niż domyślny dostawca kryptograficzny systemu Windows. Jednym z przykładów alternatywnego dostawcy kryptograficznego jest sprzętowy moduł zabezpieczeń, który wykonuje wszystkie operacje kryptograficzne związane z kluczem prywatnym i nie przechowuje kluczy prywatnych w pamięci, co zwiększa bezpieczeństwo systemu.
Poniższy przykład dotyczy tylko celów demonstracyjnych. Nie zastępuje domyślnego dostawcy usług kryptograficznych systemu Windows, ale pokazuje, gdzie można zintegrować takiego dostawcę.
z konkretnym obiektem
Każdy token zabezpieczający, który ma skojarzony klucz zabezpieczeń lub klucze, musi zaimplementować SecurityKeys właściwość, która zwraca kolekcję kluczy z wystąpienia tokenu zabezpieczającego. Jeśli token jest tokenem zabezpieczającym X.509, kolekcja zawiera pojedyncze wystąpienie X509AsymmetricSecurityKey klasy, która reprezentuje zarówno klucze publiczne, jak i prywatne skojarzone z certyfikatem. Aby zastąpić domyślnego dostawcę kryptograficznego używanego do udostępniania kluczy certyfikatu, utwórz nową implementację tej klasy.
Aby utworzyć niestandardowy klucz asymetryczny X.509
Zdefiniuj nową klasę pochodzącą X509AsymmetricSecurityKey z klasy .
Zastąpij KeySize właściwość tylko do odczytu. Ta właściwość zwraca rzeczywisty rozmiar klucza pary kluczy publicznych/prywatnych certyfikatu.
Zastąpij metodę DecryptKey . Ta metoda jest wywoływana przez strukturę zabezpieczeń WCF w celu odszyfrowania klucza symetrycznego przy użyciu klucza prywatnego certyfikatu. (Klucz został wcześniej zaszyfrowany przy użyciu klucza publicznego certyfikatu).
Zastąpij metodę GetAsymmetricAlgorithm . Ta metoda jest wywoływana przez strukturę zabezpieczeń WCF w celu uzyskania wystąpienia klasy reprezentującego AsymmetricAlgorithm dostawcę kryptograficznego dla klucza prywatnego lub publicznego certyfikatu, w zależności od parametrów przekazanych do metody.
Opcjonalny. Zastąpij metodę GetHashAlgorithmForSignature . Zastąpi tę metodę, jeśli wymagana jest inna implementacja HashAlgorithm klasy.
Zastąpij metodę GetSignatureFormatter . Ta metoda zwraca wystąpienie AsymmetricSignatureFormatter klasy skojarzonej z kluczem prywatnym certyfikatu.
Zastąpij metodę IsSupportedAlgorithm . Ta metoda służy do wskazywania, czy określony algorytm kryptograficzny jest obsługiwany przez implementację klucza zabezpieczeń.
class CustomX509AsymmetricSecurityKey : X509AsymmetricSecurityKey { X509Certificate2 certificate; object thisLock = new Object(); bool privateKeyAvailabilityDetermined; AsymmetricAlgorithm privateKey; PublicKey publicKey; public CustomX509AsymmetricSecurityKey(X509Certificate2 certificate) : base(certificate) { this.certificate = certificate; } public override int KeySize { get { return this.PublicKey.Key.KeySize; } } AsymmetricAlgorithm PrivateKey { // You need to modify this to obtain the private key using a different cryptographic // provider if you do not want to use the default provider. get { if (!this.privateKeyAvailabilityDetermined) { lock (ThisLock) { if (!this.privateKeyAvailabilityDetermined) { this.privateKey = this.certificate.PrivateKey; this.privateKeyAvailabilityDetermined = true; } } } return this.privateKey; } } PublicKey PublicKey { get { if (this.publicKey == null) { lock (ThisLock) { this.publicKey ??= this.certificate.PublicKey; } } return this.publicKey; } } Object ThisLock { get { return thisLock; } } public override byte[] DecryptKey(string algorithm, byte[] keyData) { // You can decrypt the key only if you have the private key in the certificate. if (this.PrivateKey == null) { throw new NotSupportedException("Missing private key"); } RSA rsa = this.PrivateKey as RSA; if (rsa == null) { throw new NotSupportedException("Private key cannot be used with RSA algorithm"); } // Support exchange keySpec, AT_EXCHANGE ? if (rsa.KeyExchangeAlgorithm == null) { throw new NotSupportedException("Private key does not support key exchange"); } switch (algorithm) { case EncryptedXml.XmlEncRSA15Url: return EncryptedXml.DecryptKey(keyData, rsa, false); case EncryptedXml.XmlEncRSAOAEPUrl: return EncryptedXml.DecryptKey(keyData, rsa, true); default: throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)); } } public override AsymmetricAlgorithm GetAsymmetricAlgorithm(string algorithm, bool privateKey) { if (privateKey) { if (this.PrivateKey == null) { throw new NotSupportedException("Missing private key"); } switch (algorithm) { case SignedXml.XmlDsigDSAUrl: if ((this.PrivateKey as DSA) != null) { return (this.PrivateKey as DSA); } throw new NotSupportedException("Private key cannot be used with DSA"); case SignedXml.XmlDsigRSASHA1Url: case EncryptedXml.XmlEncRSA15Url: case EncryptedXml.XmlEncRSAOAEPUrl: if ((this.PrivateKey as RSA) != null) { return (this.PrivateKey as RSA); } throw new NotSupportedException("Private key cannot be used with RSA"); default: throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)); } } else { switch (algorithm) { case SignedXml.XmlDsigDSAUrl: if ((this.PublicKey.Key as DSA) != null) { return (this.PublicKey.Key as DSA); } throw new NotSupportedException("Public key cannot be used with DSA"); case SignedXml.XmlDsigRSASHA1Url: case EncryptedXml.XmlEncRSA15Url: case EncryptedXml.XmlEncRSAOAEPUrl: if ((this.PublicKey.Key as RSA) != null) { return (this.PublicKey.Key as RSA); } throw new NotSupportedException("Public key cannot be used with RSA"); default: throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)); } } } public override HashAlgorithm GetHashAlgorithmForSignature(string algorithm) { if (!this.IsSupportedAlgorithm(algorithm)) { throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)); } switch (algorithm) { case SignedXml.XmlDsigDSAUrl: case SignedXml.XmlDsigRSASHA1Url: return new SHA1Managed(); default: throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)); } } public override AsymmetricSignatureFormatter GetSignatureFormatter(string algorithm) { // The signature can be created only if the private key is present. if (this.PrivateKey == null) { throw new NotSupportedException("Private key is missing"); } // Only one of the two algorithms is supported, not both. // XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; // XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; switch (algorithm) { case SignedXml.XmlDsigDSAUrl: // Ensure that this is a DSA algorithm object. DSA dsa = (this.PrivateKey as DSA); if (dsa == null) { throw new NotSupportedException("Private key cannot be used DSA"); } return new DSASignatureFormatter(dsa); case SignedXml.XmlDsigRSASHA1Url: // Ensure that this is an RSA algorithm object. RSA rsa = (this.PrivateKey as RSA); if (rsa == null) { throw new NotSupportedException("Private key cannot be used RSA"); } return new RSAPKCS1SignatureFormatter(rsa); default: throw new NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)); } } public override bool IsSupportedAlgorithm(string algorithm) { switch (algorithm) { case SignedXml.XmlDsigDSAUrl: return (this.PublicKey.Key is DSA); case SignedXml.XmlDsigRSASHA1Url: case EncryptedXml.XmlEncRSA15Url: case EncryptedXml.XmlEncRSAOAEPUrl: return (this.PublicKey.Key is RSA); default: return false; } } }
Friend Class CustomX509AsymmetricSecurityKey Inherits X509AsymmetricSecurityKey Private _certificate As X509Certificate2 Private _thisLock As New Object() Private _privateKeyAvailabilityDetermined As Boolean Private _privateKey As AsymmetricAlgorithm Private _publicKey As PublicKey Public Sub New(ByVal certificate As X509Certificate2) MyBase.New(certificate) Me._certificate = certificate End Sub Public Overrides ReadOnly Property KeySize() As Integer Get Return Me.PublicKey.Key.KeySize End Get End Property Private Overloads ReadOnly Property PrivateKey() As AsymmetricAlgorithm ' You need to modify this to obtain the private key using a different cryptographic ' provider if you do not want to use the default provider. Get If Not Me._privateKeyAvailabilityDetermined Then SyncLock ThisLock If Not Me._privateKeyAvailabilityDetermined Then Me._privateKey = Me._certificate.PrivateKey Me._privateKeyAvailabilityDetermined = True End If End SyncLock End If Return Me._privateKey End Get End Property Private Overloads ReadOnly Property PublicKey() As PublicKey Get If Me._publicKey Is Nothing Then SyncLock ThisLock If Me._publicKey Is Nothing Then Me._publicKey = Me._certificate.PublicKey End If End SyncLock End If Return Me._publicKey End Get End Property Private Overloads ReadOnly Property ThisLock() As Object Get Return _thisLock End Get End Property Public Overrides Function DecryptKey(ByVal algorithm As String, _ ByVal keyData() As Byte) As Byte() ' You can decrypt the key only if you have the private key in the certificate. If Me.PrivateKey Is Nothing Then Throw New NotSupportedException("Missing private key") End If Dim rsa = TryCast(Me.PrivateKey, RSA) If rsa Is Nothing Then Throw New NotSupportedException("Private key cannot be used with RSA algorithm") End If ' Support exchange keySpec, AT_EXCHANGE ? If rsa.KeyExchangeAlgorithm Is Nothing Then Throw New NotSupportedException("Private key does not support key exchange") End If Select Case algorithm Case EncryptedXml.XmlEncRSA15Url Return EncryptedXml.DecryptKey(keyData, rsa, False) Case EncryptedXml.XmlEncRSAOAEPUrl Return EncryptedXml.DecryptKey(keyData, rsa, True) Case Else Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)) End Select End Function Public Overrides Function GetAsymmetricAlgorithm(ByVal algorithm As String, _ ByVal privateKey As Boolean) As AsymmetricAlgorithm If privateKey Then If Me.PrivateKey Is Nothing Then Throw New NotSupportedException("Missing private key") End If Select Case algorithm Case SignedXml.XmlDsigDSAUrl If TryCast(Me.PrivateKey, DSA) IsNot Nothing Then Return (TryCast(Me.PrivateKey, DSA)) End If Throw New NotSupportedException("Private key cannot be used with DSA") Case SignedXml.XmlDsigRSASHA1Url, EncryptedXml.XmlEncRSA15Url, EncryptedXml.XmlEncRSAOAEPUrl If TryCast(Me.PrivateKey, RSA) IsNot Nothing Then Return (TryCast(Me.PrivateKey, RSA)) End If Throw New NotSupportedException("Private key cannot be used with RSA") Case Else Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)) End Select Else Select Case algorithm Case SignedXml.XmlDsigDSAUrl If TryCast(Me.PublicKey.Key, DSA) IsNot Nothing Then Return (TryCast(Me.PublicKey.Key, DSA)) End If Throw New NotSupportedException("Public key cannot be used with DSA") Case SignedXml.XmlDsigRSASHA1Url, EncryptedXml.XmlEncRSA15Url, EncryptedXml.XmlEncRSAOAEPUrl If TryCast(Me.PublicKey.Key, RSA) IsNot Nothing Then Return (TryCast(Me.PublicKey.Key, RSA)) End If Throw New NotSupportedException("Public key cannot be used with RSA") Case Else Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)) End Select End If End Function Public Overrides Function GetHashAlgorithmForSignature(ByVal algorithm As String) As HashAlgorithm If Not Me.IsSupportedAlgorithm(algorithm) Then Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)) End If Select Case algorithm Case SignedXml.XmlDsigDSAUrl, SignedXml.XmlDsigRSASHA1Url Return New SHA1Managed() Case Else Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)) End Select End Function Public Overrides Function GetSignatureFormatter(ByVal algorithm As String) As AsymmetricSignatureFormatter ' The signature can be created only if the private key is present. If Me.PrivateKey Is Nothing Then Throw New NotSupportedException("Private key is missing") End If ' Only one of the two algorithms is supported, not both. ' XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; ' XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; Select Case algorithm Case SignedXml.XmlDsigDSAUrl ' Ensure that this is a DSA algorithm object. Dim dsa = (TryCast(Me.PrivateKey, DSA)) If dsa Is Nothing Then Throw New NotSupportedException("Private key cannot be used DSA") End If Return New DSASignatureFormatter(dsa) Case SignedXml.XmlDsigRSASHA1Url ' Ensure that this is an RSA algorithm object. Dim rsa = (TryCast(Me.PrivateKey, RSA)) If rsa Is Nothing Then Throw New NotSupportedException("Private key cannot be used RSA") End If Return New RSAPKCS1SignatureFormatter(rsa) Case Else Throw New NotSupportedException(String.Format("Algorithm {0} is not supported", algorithm)) End Select End Function Public Overrides Function IsSupportedAlgorithm(ByVal algorithm As String) As Boolean Select Case algorithm Case SignedXml.XmlDsigDSAUrl Return (TypeOf Me.PublicKey.Key Is DSA) Case SignedXml.XmlDsigRSASHA1Url, EncryptedXml.XmlEncRSA15Url, EncryptedXml.XmlEncRSAOAEPUrl Return (TypeOf Me.PublicKey.Key Is RSA) Case Else Return False End Select End Function End Class
Poniższa procedura pokazuje, jak zintegrować niestandardową implementację asymetrycznego klucza zabezpieczeń X.509 utworzoną w poprzedniej procedurze z platformą zabezpieczeń WCF w celu zastąpienia dostarczonego przez system tokenu zabezpieczającego X.509.
Aby zastąpić udostępniony przez system token zabezpieczający X.509 niestandardowym tokenem asymetrycznym klucza zabezpieczającego X.509
Utwórz niestandardowy token zabezpieczający X.509, który zwraca niestandardowy asymetryczny klucz zabezpieczeń X.509 zamiast klucza zabezpieczeń dostarczonego przez system, jak pokazano w poniższym przykładzie. Aby uzyskać więcej informacji na temat niestandardowych tokenów zabezpieczających, zobacz Instrukcje: tworzenie tokenu niestandardowego.
class CustomX509SecurityToken : X509SecurityToken { ReadOnlyCollection<SecurityKey> securityKeys; public CustomX509SecurityToken(X509Certificate2 certificate) : base(certificate) { } public override ReadOnlyCollection<SecurityKey> SecurityKeys { get { if (this.securityKeys == null) { List<SecurityKey> temp = new List<SecurityKey>(1); temp.Add(new CustomX509AsymmetricSecurityKey(this.Certificate)); this.securityKeys = temp.AsReadOnly(); } return this.securityKeys; } } }
Friend Class CustomX509SecurityToken Inherits X509SecurityToken Private _securityKeys As ReadOnlyCollection(Of SecurityKey) Public Sub New(ByVal certificate As X509Certificate2) MyBase.New(certificate) End Sub Public Overrides ReadOnly Property SecurityKeys() As ReadOnlyCollection(Of SecurityKey) Get If Me._securityKeys Is Nothing Then Dim temp As New List(Of SecurityKey)(1) temp.Add(New CustomX509AsymmetricSecurityKey(Me.Certificate)) Me._securityKeys = temp.AsReadOnly() End If Return Me._securityKeys End Get End Property End Class
Utwórz niestandardowego dostawcę tokenu zabezpieczającego, który zwraca niestandardowy token zabezpieczający X.509, jak pokazano w przykładzie. Aby uzyskać więcej informacji na temat niestandardowych dostawców tokenów zabezpieczających, zobacz How to: Create a Custom Security Token Provider (Instrukcje: tworzenie niestandardowego dostawcy tokenów zabezpieczających).
class CustomX509SecurityTokenProvider : SecurityTokenProvider { X509Certificate2 certificate; public CustomX509SecurityTokenProvider(X509Certificate2 certificate) { this.certificate = certificate; } protected override SecurityToken GetTokenCore(TimeSpan timeout) { return new CustomX509SecurityToken(certificate); } }
Friend Class CustomX509SecurityTokenProvider Inherits SecurityTokenProvider Private _certificate As X509Certificate2 Public Sub New(ByVal certificate As X509Certificate2) Me._certificate = certificate End Sub Protected Overrides Function GetTokenCore(ByVal timeout As TimeSpan) As SecurityToken Return New CustomX509SecurityToken(_certificate) End Function End Class
Jeśli niestandardowy klucz zabezpieczeń musi być używany po stronie inicjatora, utwórz niestandardowy menedżer tokenów zabezpieczeń klienta i niestandardowe klasy poświadczeń klienta, jak pokazano w poniższym przykładzie. Aby uzyskać więcej informacji na temat niestandardowych poświadczeń klienta i menedżerów tokenów zabezpieczeń klienta, zobacz Przewodnik: tworzenie niestandardowych poświadczeń klienta i usługi.
class CustomClientSecurityTokenManager : ClientCredentialsSecurityTokenManager { CustomClientCredentials credentials; public CustomClientSecurityTokenManager(CustomClientCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { SecurityTokenProvider result = null; if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate) { MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>(ServiceModelSecurityTokenRequirement.MessageDirectionProperty); if (direction == MessageDirection.Output) { if (tokenRequirement.KeyUsage == SecurityKeyUsage.Signature) { result = new CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate); } } else { if (tokenRequirement.KeyUsage == SecurityKeyUsage.Exchange) { result = new CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate); } } } result ??= base.CreateSecurityTokenProvider(tokenRequirement); return result; } }
Friend Class CustomClientSecurityTokenManager Inherits ClientCredentialsSecurityTokenManager Private credentials As CustomClientCredentials Public Sub New(ByVal credentials As CustomClientCredentials) MyBase.New(credentials) Me.credentials = credentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) _ As SecurityTokenProvider Dim result As SecurityTokenProvider = Nothing If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then Dim direction = tokenRequirement.GetProperty(Of MessageDirection) _ (ServiceModelSecurityTokenRequirement.MessageDirectionProperty) If direction = MessageDirection.Output Then If tokenRequirement.KeyUsage = SecurityKeyUsage.Signature Then result = New CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate) End If Else If tokenRequirement.KeyUsage = SecurityKeyUsage.Exchange Then result = New CustomX509SecurityTokenProvider(credentials.ClientCertificate.Certificate) End If End If End If If result Is Nothing Then result = MyBase.CreateSecurityTokenProvider(tokenRequirement) End If Return result End Function End Class
public class CustomClientCredentials : ClientCredentials { public CustomClientCredentials() { } protected CustomClientCredentials(CustomClientCredentials other) : base(other) { } protected override ClientCredentials CloneCore() { return new CustomClientCredentials(this); } public override SecurityTokenManager CreateSecurityTokenManager() { return new CustomClientSecurityTokenManager(this); } }
Public Class CustomClientCredentials Inherits ClientCredentials Public Sub New() End Sub Protected Sub New(ByVal other As CustomClientCredentials) MyBase.New(other) End Sub Protected Overrides Function CloneCore() As ClientCredentials Return New CustomClientCredentials(Me) End Function Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New CustomClientSecurityTokenManager(Me) End Function End Class
Jeśli niestandardowy klucz zabezpieczeń musi być używany po stronie adresata, utwórz niestandardowy menedżer tokenów zabezpieczających usługi i poświadczenia usługi niestandardowej, jak pokazano w poniższym przykładzie. Aby uzyskać więcej informacji na temat niestandardowych poświadczeń usługi i menedżerów tokenów zabezpieczających usługi, zobacz Przewodnik: tworzenie niestandardowych poświadczeń klienta i usługi.
class CustomServiceSecurityTokenManager : ServiceCredentialsSecurityTokenManager { CustomServiceCredentials credentials; public CustomServiceSecurityTokenManager(CustomServiceCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { SecurityTokenProvider result = null; if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate) { MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>(ServiceModelSecurityTokenRequirement.MessageDirectionProperty); if (direction == MessageDirection.Input) { if (tokenRequirement.KeyUsage == SecurityKeyUsage.Exchange) { result = new CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate); } } else { if (tokenRequirement.KeyUsage == SecurityKeyUsage.Signature) { result = new CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate); } } } result ??= base.CreateSecurityTokenProvider(tokenRequirement); return result; } }
Friend Class CustomServiceSecurityTokenManager Inherits ServiceCredentialsSecurityTokenManager Private credentials As CustomServiceCredentials Public Sub New(ByVal credentials As CustomServiceCredentials) MyBase.New(credentials) Me.credentials = credentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider Dim result As SecurityTokenProvider = Nothing If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then Dim direction = tokenRequirement.GetProperty(Of MessageDirection) _ (ServiceModelSecurityTokenRequirement.MessageDirectionProperty) If direction = MessageDirection.Input Then If tokenRequirement.KeyUsage = SecurityKeyUsage.Exchange Then result = New CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate) End If Else If tokenRequirement.KeyUsage = SecurityKeyUsage.Signature Then result = New CustomX509SecurityTokenProvider(credentials.ServiceCertificate.Certificate) End If End If End If If result Is Nothing Then result = MyBase.CreateSecurityTokenProvider(tokenRequirement) End If Return result End Function End Class
public class CustomServiceCredentials : ServiceCredentials { public CustomServiceCredentials() { } protected CustomServiceCredentials(CustomServiceCredentials other) : base(other) { } protected override ServiceCredentials CloneCore() { return new CustomServiceCredentials(this); } public override SecurityTokenManager CreateSecurityTokenManager() { return new CustomServiceSecurityTokenManager(this); } }
Public Class CustomServiceCredentials Inherits ServiceCredentials Public Sub New() End Sub Protected Sub New(ByVal other As CustomServiceCredentials) MyBase.New(other) End Sub Protected Overrides Function CloneCore() As ServiceCredentials Return New CustomServiceCredentials(Me) End Function Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New CustomServiceSecurityTokenManager(Me) End Function End Class
Zobacz też
- X509AsymmetricSecurityKey
- AsymmetricSecurityKey
- SecurityKey
- AsymmetricAlgorithm
- HashAlgorithm
- AsymmetricSignatureFormatter
- Przewodnik: tworzenie niestandardowego klienta i poświadczeń usługi
- Instrukcje: tworzenie niestandardowego wystawcy uwierzytelniania tokenu zabezpieczeń
- Instrukcje: tworzenie niestandardowego dostawcy tokenów zabezpieczeń
- Instrukcje: tworzenie tokenu niestandardowego