共用方式為


HOW TO:建立使用自訂憑證驗證程式的服務

這個主題將示範如何實作自訂憑證驗證程式,以及如何設定用戶端或服務認證,以使用自訂憑證驗證程式來取代預設的憑證驗證邏輯。

如果使用 X.509 憑證來驗證用戶端或服務,根據預設,Windows Communication Foundation (WCF) 會使用 Windows 憑證存放區和 Crypto API 來驗證憑證及確保它是受信任的。有時內建的憑證驗證功能不足,而必須變更。WCF 提供一種簡單的方法,可允許使用者新增憑證驗證程式以變更驗證邏輯。如果指定了自訂憑證驗證程式,WCF 便不會使用內建的憑證驗證邏輯,而會改用自訂驗證程式。

程序

建立自訂憑證驗證程式

  1. 請定義從 X509CertificateValidator 衍生的新類別。

  2. 實作抽象的 Validate 方法。必須驗證的憑證會傳遞為方法的引數。如果根據驗證邏輯,傳遞的憑證是無效的,這個方法會擲回 SecurityTokenValidationException。如果憑證是有效的,方法會傳回至呼叫者。

    ms733806.note(zh-tw,VS.100).gif注意:
    若要將驗證錯誤傳回至用戶端,請在 Validate 方法中擲回 FaultException

Public Class MyX509CertificateValidator
    Inherits X509CertificateValidator
    Private allowedIssuerName As String
    
    Public Sub New(ByVal allowedIssuerName As String) 
        If allowedIssuerName Is Nothing Then
            Throw New ArgumentNullException("allowedIssuerName")
        End If
        
        Me.allowedIssuerName = allowedIssuerName
    
    End Sub 
        
    Public Overrides Sub Validate(ByVal certificate As X509Certificate2) 
        ' Check that there is a certificate.
        If certificate Is Nothing Then
            Throw New ArgumentNullException("certificate")
        End If
        
        ' Check that the certificate issuer matches the configured issuer.
        If allowedIssuerName <> certificate.IssuerName.Name Then
            Throw New SecurityTokenValidationException _
              ("Certificate was not issued by a trusted issuer")
        End If
    
    End Sub 
End Class 
public class MyX509CertificateValidator : X509CertificateValidator
{
    string allowedIssuerName;

    public MyX509CertificateValidator(string allowedIssuerName)
    {
        if (allowedIssuerName == null)
        {
            throw new ArgumentNullException("allowedIssuerName");
        }

        this.allowedIssuerName = allowedIssuerName;
    }

    public override void Validate(X509Certificate2 certificate)
    {
        // Check that there is a certificate.
        if (certificate == null)
        {
            throw new ArgumentNullException("certificate");
        }

        // Check that the certificate issuer matches the configured issuer.
        if (allowedIssuerName != certificate.IssuerName.Name)
        {
            throw new SecurityTokenValidationException
              ("Certificate was not issued by a trusted issuer");
        }
    }
}

在服務組態中指定自訂憑證驗證程式

  1. <behaviors> 項目和 serviceBehaviors section加入至 <system.ServiceModel> 項目。

  2. 新增 Behavior element,然後將 name 屬性設定為適當的值。

  3. <serviceCredentials> Element加入至 <behavior> 項目。

  4. <clientCertificate> 項目加入至 <serviceCredentials> 項目。

  5. <authentication> of <clientCertificate> Element加入至 <clientCertificate> 項目。

  6. customCertificateValidatorType 屬性設定為驗證程式類型。下列範例會將屬性設定為類型的命名空間和名稱。

  7. certificateValidationMode 屬性設定為 Custom

    <configuration>
     <system.serviceModel>
      <behaviors>
       <serviceBehaviors>
        <behavior name="ServiceBehavior">
         <serviceCredentials>
          <clientCertificate>
          <authentication certificateValidationMode="Custom" customCertificateValidatorType="Samples.MyValidator, service" />
          </clientCertificate>
         </serviceCredentials>
        </behavior>
       </serviceBehaviors>
      </behaviors>
    </system.serviceModel>
    </configuration>
    

使用用戶端上的組態來指定自訂憑證驗證程式

  1. <behaviors> 項目和 serviceBehaviors section加入至 <system.ServiceModel> 項目。

  2. 新增 <endpointBehaviors> 項目。

  3. 加入 <behavior> 項目,並將 name 屬性設定為適當值。

  4. 新增 <clientCredentials> 項目。

  5. 新增 <serviceCertificate> of <clientCredentials> Element

  6. 新增 <authentication> of <serviceCertificate> Element,如下列範例所示。

  7. customCertificateValidatorType 屬性設定為驗證程式類型。

  8. certificateValidationMode 屬性設定為 Custom。下列範例會將屬性設定為類型的命名空間和名稱。

    <configuration>
     <system.serviceModel>
      <behaviors>
       <endpointBehaviors>
        <behavior name="clientBehavior">
         <clientCredentials>
          <serviceCertificate>
           <authentication certificateValidationMode="Custom" 
                  customCertificateValidatorType=
             "Samples.CustomX509CertificateValidator, client"/>
          </serviceCertificate>
         </clientCredentials>
        </behavior>
       </endpointBehaviors>
      </behaviors>
     </system.serviceModel>
    </configuration>
    

使用服務上的程式碼來指定自訂憑證驗證程式

  1. 請在 ClientCertificate 屬性上指定自訂憑證驗證程式。您可以使用 Credentials 屬性來存取服務認證。

  2. CertificateValidationMode 屬性設定為 Custom

serviceHost.Credentials.ClientCertificate.Authentication. _
    CertificateValidationMode = X509CertificateValidationMode.Custom
serviceHost.Credentials.ClientCertificate.Authentication. _
   CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = 
    X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
    new MyX509CertificateValidator("CN=Contoso.com");

使用用戶端上的程式碼來指定自訂憑證驗證程式

  1. 請使用 CustomCertificateValidator 屬性來指定自訂憑證驗證程式。您可以使用 Credentials 屬性來存取用戶端認證。(由 ServiceModel 中繼資料公用程式工具 (Svcutil.exe) 產生的用戶端類別永遠是衍生自 ClientBase 類別)。

  2. CertificateValidationMode 屬性設定為 Custom

範例

描述

下列範例將示範在服務上實作自訂憑證驗證程式及其使用方式。

程式碼

Imports System
Imports System.IdentityModel.Selectors
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Permissions

<assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution := True)>
<ServiceContract([Namespace] := "http://Microsoft.ServiceModel.Samples")>  _
Public Interface ICalculator
    <OperationContract()>  _
    Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double 
End Interface 


Public Class CalculatorService
    Implements ICalculator
    
    Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double _
       Implements ICalculator.Add
        Dim result As Double = n1 + n2
        Return result    
    End Function 
End Class 


Class Program
    
    Shared Sub Main() 
        Dim serviceHost As New ServiceHost(GetType(CalculatorService))
        Try
            serviceHost.Credentials.ClientCertificate.Authentication. _
                CertificateValidationMode = X509CertificateValidationMode.Custom
            serviceHost.Credentials.ClientCertificate.Authentication. _
               CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
            serviceHost.Open()
            Console.WriteLine("Service started, press ENTER to stop ...")
            Console.ReadLine()
            
            serviceHost.Close()
        Finally
            serviceHost.Close()
        End Try
    
    End Sub 
End Class 

Public Class MyX509CertificateValidator
    Inherits X509CertificateValidator
    Private allowedIssuerName As String
    
    Public Sub New(ByVal allowedIssuerName As String) 
        If allowedIssuerName Is Nothing Then
            Throw New ArgumentNullException("allowedIssuerName")
        End If
        
        Me.allowedIssuerName = allowedIssuerName
    
    End Sub 
        
    Public Overrides Sub Validate(ByVal certificate As X509Certificate2) 
        ' Check that there is a certificate.
        If certificate Is Nothing Then
            Throw New ArgumentNullException("certificate")
        End If
        
        ' Check that the certificate issuer matches the configured issuer.
        If allowedIssuerName <> certificate.IssuerName.Name Then
            Throw New SecurityTokenValidationException _
              ("Certificate was not issued by a trusted issuer")
        End If
    
    End Sub 
End Class 
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;

using System.Security.Permissions;

[assembly: SecurityPermission(
   SecurityAction.RequestMinimum, Execution = true)]
namespace Microsoft.ServiceModel.Samples
{ 
    [ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator
    {
        [OperationContract]
        double Add(double n1, double n2);
    }

    public class CalculatorService : ICalculator
    {
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }
    }

    class Program
    {
        static void Main()
        {
            using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
            {
                serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = 
                    X509CertificateValidationMode.Custom;
                serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
                    new MyX509CertificateValidator("CN=Contoso.com");

                serviceHost.Open();
                Console.WriteLine("Service started, press ENTER to stop ...");
                Console.ReadLine();

                serviceHost.Close();
            }
        }
    }

    public class MyX509CertificateValidator : X509CertificateValidator
    {
        string allowedIssuerName;

        public MyX509CertificateValidator(string allowedIssuerName)
        {
            if (allowedIssuerName == null)
            {
                throw new ArgumentNullException("allowedIssuerName");
            }

            this.allowedIssuerName = allowedIssuerName;
        }

        public override void Validate(X509Certificate2 certificate)
        {
            // Check that there is a certificate.
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            // Check that the certificate issuer matches the configured issuer.
            if (allowedIssuerName != certificate.IssuerName.Name)
            {
                throw new SecurityTokenValidationException
                  ("Certificate was not issued by a trusted issuer");
            }
        }
    }
}

另請參閱

參考

X509CertificateValidator