Comment : remplacer le fournisseur de services de chiffrement par la clé privée d'un certificat X.509
Cette rubrique montre comment modifier le fournisseur de services de chiffrement utilisé pour fournir la clé privée d'un certificat X.509 et comment intégrer le fournisseur dans l'infrastructure de la sécurité Windows Communication Foundation (WCF). Pour plus d'informations sur l'utilisation des certificats, consultez Utilisation des certificats.
L'infrastructure de la sécurité WCF fournit une méthode pour introduire de nouveaux types de jeton de sécurité comme décrit dans Comment : créer un jeton personnalisé. Vous pouvez aussi utiliser un jeton personnalisé pour remplacer les types de jeton existants fournis par le système.
Dans cette rubrique, le jeton de sécurité X.509 fourni par le système est remplacé par un jeton X.509 personnalisé qui fournit une implémentation différente pour la clé privée de certificat. Cette opération est utile dans les scénarios où la clé privée à proprement dite est fournie par un fournisseur de services de chiffrement différent du fournisseur Windows par défaut. Parmi les exemples d'un autre fournisseur de services de chiffrement figure un module de la sécurité du matériel qui effectue toutes les opérations de chiffrement liées à la clé privée sans stocker les clés privées en mémoire, ce qui améliore la sécurité du système.
L'exemple suivant est fourni à des fins de démonstration uniquement. Il ne remplace pas le fournisseur de services de chiffrement Windows par défaut, mais il montre comment intégrer ce type de fournisseur.
Procédures
Chaque jeton de sécurité qui possède une clé ou des clés de sécurité associées doit implémenter la propriété SecurityKeys qui retourne une collection de clés issue de l'instance du jeton de sécurité. Si le jeton est un jeton de sécurité X.509, la collection contient une instance unique de la classe X509AsymmetricSecurityKey qui représente à la fois les clés privées et publiques associées au certificat. Pour remplacer le fournisseur de services de chiffrement par défaut utilisé pour fournir les clés du certificat, créez une nouvelle implémentation de cette classe.
Pour créer une clé asymétrique X.509 personnalisée
Définissez une nouvelle classe dérivée de la classe X509AsymmetricSecurityKey.
Substituez la propriété en lecture seule KeySize. Cette propriété retourne la taille de clé réelle de la paire de clés publique/privée du certificat.
Substituez la méthode DecryptKey. Cette méthode est appelée par l'infrastructure de la sécurité WCF pour déchiffrer une clé symétrique avec la clé privée du certificat. (La clé a été chiffrée précédemment avec la clé publique du certificat.)
Substituez la méthode GetAsymmetricAlgorithm. Cette méthode est appelée par l'infrastructure de la sécurité WCF pour obtenir une instance de la classe AsymmetricAlgorithm qui représente le fournisseur de services de chiffrement pour la clé privée ou publique du certificat selon les paramètres passés à la méthode.
Facultatif. Substituez la méthode GetHashAlgorithmForSignature. Substituez cette méthode si une implémentation différente de la classe HashAlgorithm est requise.
Substituez la méthode GetSignatureFormatter. Cette méthode retourne une instance de la classe AsymmetricSignatureFormatter associée à la clé privée du certificat.
Substituez la méthode IsSupportedAlgorithm. Cette méthode est utilisée pour indiquer si un algorithme de chiffrement particulier est pris en charge par l'implémentation de la clé de sécurité.
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
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) { if (this.publicKey == null) { 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; } } }
La procédure suivante indique comment intégrer l'implémentation de la clé de sécurité asymétrique personnalisée X.509 créée au cours de la procédure précédente à l'aide de l'infrastructure de la sécurité WCF afin de remplacer le jeton de sécurité X.509 fourni par le système.
Pour remplacer le jeton de sécurité X.509 fourni par le système par un jeton de clé de sécurité asymétrique X.509 personnalisé
Créez un jeton de sécurité X.509 personnalisé qui retourne la clé de sécurité asymétrique X.509 personnalisée au lieu de la clé de sécurité fournie par le système, comme indiqué dans l'exemple suivant. Pour plus d'informations sur les jetons de sécurité personnalisés, consultez Comment : créer un jeton personnalisé.
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
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; } } }
Créez un fournisseur de jetons de sécurité personnalisé qui retourne un jeton de sécurité X.509 personnalisé, comme indiqué dans l'exemple. Pour plus d'informations sur les fournisseurs de jetons de sécurité personnalisés, consultez Comment : créer un fournisseur de jetons de sécurité personnalisé.
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
class CustomX509SecurityTokenProvider : SecurityTokenProvider { X509Certificate2 certificate; public CustomX509SecurityTokenProvider(X509Certificate2 certificate) { this.certificate = certificate; } protected override SecurityToken GetTokenCore(TimeSpan timeout) { return new CustomX509SecurityToken(certificate); } }
Si la clé de sécurité personnalisée doit être utilisée sur le côté d'initiateur, créez un gestionnaire de jetons de sécurité client personnalisé et des classes d'informations d'identification du client personnalisées, comme indiqué dans l'exemple suivant. Pour plus d'informations sur les informations d'identification personnalisées du client et les gestionnaires de jetons de sécurité client, consultez Procédure pas à pas : création d'informations d'identification de client et de service personnalisées.
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
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); } } } if (result == null) { result = base.CreateSecurityTokenProvider(tokenRequirement); } return result; } }
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
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); } }
Si la clé de sécurité personnalisée doit être utilisée sur le côté destinataire, créez un gestionnaire de jetons de sécurité client personnalisé et des classes personnalisées d'informations d'identification du client, comme indiqué dans l'exemple suivant. Pour plus d'informations sur les informations d'identification de services personnalisées et les gestionnaires de jetons de sécurité de service, consultez Procédure pas à pas : création d'informations d'identification de client et de service personnalisées.
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
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); } } } if (result == null) { result = base.CreateSecurityTokenProvider(tokenRequirement); } return result; } }
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
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); } }
Voir aussi
Tâches
Comment : créer un fournisseur de jetons de sécurité personnalisé
Référence
X509AsymmetricSecurityKey
AsymmetricSecurityKey
SecurityKey
AsymmetricAlgorithm
HashAlgorithm
AsymmetricSignatureFormatter
Concepts
Procédure pas à pas : création d'informations d'identification de client et de service personnalisées
Comment : créer un authentificateur de jetons de sécurité personnalisé
Comment : créer un jeton personnalisé
Architecture de sécurité