如何:使用自定义用户名和密码验证程序

默认情况下,当用户名和密码用于身份验证时,Windows Communication Foundation (WCF) 会使用 Windows 来验证用户名和密码。不过,WCF 允许自定义用户名和密码身份验证方案,也称为“验证程序”。**若要合并自定义用户名和密码验证程序,请创建一个从 UserNamePasswordValidator 派生的类,然后对其进行配置。

有关示例应用程序,请参见 用户名密码验证程序

创建自定义用户名和密码验证程序

  1. 创建一个从 UserNamePasswordValidator 派生的类。

    Public Class CustomUserNameValidator
        Inherits UserNamePasswordValidator
    
    public class CustomUserNameValidator : UserNamePasswordValidator
    {
    
  2. 通过重写 Validate 方法,实现自定义身份验证方案。

    请不要使用下面示例中的代码在生产环境中重写 Validate 方法。请将该代码替换为您的自定义用户名和密码验证方案,这可能会涉及到从数据库检索用户名和密码对。

    若要将身份验证错误返回到客户端,应在 Validate 方法中引发 FaultException

    ' This method validates users. It allows in two users, test1 and test2 
    ' with passwords 1tset and 2tset respectively.
    ' This code is for illustration purposes only and 
    ' must not be used in a production environment because it is not secure.    
    Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
        If Nothing = userName OrElse Nothing = password Then
            Throw New ArgumentNullException()
        End If
    
        If Not (userName = "test1" AndAlso password = "1tset") AndAlso Not (userName = "test2" AndAlso password = "2tset") Then
            ' This throws an informative fault to the client.
            Throw New FaultException("Unknown Username or Incorrect Password")
            ' When you do not want to throw an infomative fault to the client,
            ' throw the following exception.
            ' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
        End If
    
    End Sub
    
    // This method validates users. It allows in two users, test1 and test2 
    // with passwords 1tset and 2tset respectively.
    // This code is for illustration purposes only and 
    // must not be used in a production environment because it is not secure.    
    public override void Validate(string userName, string password)
    {
        if (null == userName || null == password)
        {
            throw new ArgumentNullException();
        }
    
        if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
        {
            // This throws an informative fault to the client.
            throw new FaultException("Unknown Username or Incorrect Password");
            // When you do not want to throw an infomative fault to the client,
            // throw the following exception.
            // throw new SecurityTokenException("Unknown Username or Incorrect Password");
        }
    }
    

配置服务以使用自定义用户名和密码验证程序

  1. 配置一个绑定,该绑定在任何传输上使用消息安全,或者在 HTTP(S) 上使用传输级安全。

    使用消息安全时,应添加系统提供的绑定之一,如 wsHttpBinding Element或支持消息安全和 UserName 凭据类型的 customBinding Element

    在 HTTP(S) 上使用传输级安全时,应添加 wsHttpBinding Element<basicHttpBinding>,或添加使用 HTTP(S) 和 Basic 身份验证方案的 <netTcpBinding>customBinding Element

    Aa702565.note(zh-cn,VS.100).gif注意:
    使用 .NET Framework 3.5 版 或更高版本时,可将自定义用户名和密码验证程序与消息和传输安全一起使用。使用 .NET Framework 3.0 时,自定义用户名和密码验证程序只能与消息安全一起使用。

    Aa702565.Tip(zh-cn,VS.100).gif提示:
    有关在此上下文中使用 <netTcpBinding> 的更多信息,请参见 <security> of <netTcpBinding>

    1. 在配置文件中,在 <system.ServiceModel> 元素下面添加一个 <bindings> 元素。

    2. 向绑定节添加 wsHttpBinding Element<basicHttpBinding> 元素。有关创建 WCF 绑定元素的更多信息,请参见如何:在配置中指定服务绑定

    3. security element of wsHttpBinding<security> of <basicHttpBinding>mode 属性设置为 MessageTransportTransportWithMessageCredential

    4. 设置 message element of wsHttpBinding<transport> of <wsHttpBinding>clientCredentialType 属性。

      使用消息安全时,将 message element of wsHttpBindingclientCredentialType 属性设置为 UserName

      在 HTTP(S) 上使用传输级安全时,将 <transport> of <wsHttpBinding><transport> of <basicHttpBinding>clientCredentialType 属性设置为 Basic

      Aa702565.note(zh-cn,VS.100).gif注意:
      如果使用传输级安全在 Internet 信息服务(IIS) 中承载 WCF 服务,并且将 UserNamePasswordValidationMode 属性设置为 Custom,则自定义身份验证方案会使用 Windows 身份验证的子集。这是因为在此情况下,IIS 会在 WCF 调用自定义验证器之前执行 Windows 身份验证。

    有关创建 WCF 绑定元素的更多信息,请参见如何:在配置中指定服务绑定

    下面的示例显示绑定的配置代码。

    <system.serviceModel> 
      <bindings>
      <wsHttpBinding>
          <binding name="Binding1">
            <security mode="Message">
              <message clientCredentialType="UserName" />
            </security>
          </binding>        
        </wsHttpBinding>
      </bindings>
    </system.serviceModel>
    
  2. 配置一个行为,该行为指定使用自定义用户名和密码验证程序来验证传入的 UserNameSecurityToken 安全令牌的用户名和密码对。

    1. 添加一个 <behaviors> 元素,将其作为 <system.serviceModel> 元素的子级。

    2. <behaviors> 元素中添加一个 serviceBehaviors section

    3. 添加一个 <behavior> 元素,并将 name 属性设置为适当的值。

    4. <behavior> 元素中添加一个 <serviceCredentials> Element

    5. <serviceCredentials> Element中添加一个 userNameAuthentication element

    6. userNamePasswordValidationMode 设置为 Custom

      Aa702565.Important(zh-cn,VS.100).gif 注意:
      如果未设置 userNamePasswordValidationMode 值,WCF 会使用 Windows 身份验证而不是自定义用户名和密码验证程序。

    7. customUserNamePasswordValidatorType 设置为表示自定义用户名和密码验证程序的类型。

    下面的示例演示至此为止的 <serviceCredentials> 片段。

    <serviceCredentials>
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService.CustomUserNameValidator, service" />
    </serviceCredentials>
    

示例

下面的代码示例演示如何创建自定义用户名和密码验证程序。请不要使用代码重写生产环境中的 Validate 方法。请将该代码替换为您的自定义用户名和密码验证方案,这可能会涉及到从数据库检索用户名和密码对。

Imports System

Imports System.IdentityModel.Selectors
Imports System.IdentityModel.Tokens

Imports System.Security.Principal

Imports System.ServiceModel

    

    
    ...
    
    

        Public Class CustomUserNameValidator
        Inherits UserNamePasswordValidator
        ' This method validates users. It allows in two users, test1 and test2 
        ' with passwords 1tset and 2tset respectively.
        ' This code is for illustration purposes only and 
        ' must not be used in a production environment because it is not secure.    
        Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
            If Nothing = userName OrElse Nothing = password Then
                Throw New ArgumentNullException()
            End If

            If Not (userName = "test1" AndAlso password = "1tset") AndAlso Not (userName = "test2" AndAlso password = "2tset") Then
                ' This throws an informative fault to the client.
                Throw New FaultException("Unknown Username or Incorrect Password")
                ' When you do not want to throw an infomative fault to the client,
                ' throw the following exception.
                ' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
            End If

        End Sub
    End Class
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;

using System.Security.Principal;

using System.ServiceModel;

    

    
    ...
    
    

    
        public class CustomUserNameValidator : UserNamePasswordValidator
        {
            // This method validates users. It allows in two users, test1 and test2 
            // with passwords 1tset and 2tset respectively.
            // This code is for illustration purposes only and 
            // must not be used in a production environment because it is not secure.   
            public override void Validate(string userName, string password)
            {
                if (null == userName || null == password)
                {
                    throw new ArgumentNullException();
                }

                if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
                {
                    // This throws an informative fault to the client.
                    throw new FaultException("Unknown Username or Incorrect Password");
                    // When you do not want to throw an infomative fault to the client,
                    // throw the following exception.
                    // throw new SecurityTokenException("Unknown Username or Incorrect Password");
                }
            }
        }

另请参见

任务

如何:使用 ASP.NET 成员资格提供程序

参考

UserNamePasswordValidator

其他资源

身份验证