如何:使用自定义用户名和密码验证程序
默认情况下,当用户名和密码用于身份验证时,Windows Communication Foundation (WCF) 会使用 Windows 来验证用户名和密码。不过,WCF 允许自定义用户名和密码身份验证方案,也称为“验证程序”。**若要合并自定义用户名和密码验证程序,请创建一个从 UserNamePasswordValidator 派生的类,然后对其进行配置。
有关示例应用程序,请参见 用户名密码验证程序。
创建自定义用户名和密码验证程序
创建一个从 UserNamePasswordValidator 派生的类。
Public Class CustomUserNameValidator Inherits UserNamePasswordValidator
public class CustomUserNameValidator : UserNamePasswordValidator {
通过重写 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"); } }
配置服务以使用自定义用户名和密码验证程序
配置一个绑定,该绑定在任何传输上使用消息安全,或者在 HTTP(S) 上使用传输级安全。
使用消息安全时,应添加系统提供的绑定之一,如 wsHttpBinding Element或支持消息安全和 UserName 凭据类型的 customBinding Element。
在 HTTP(S) 上使用传输级安全时,应添加 wsHttpBinding Element或 <basicHttpBinding>,或添加使用 HTTP(S) 和 Basic 身份验证方案的 <netTcpBinding> 或 customBinding Element。
注意: 使用 .NET Framework 3.5 版 或更高版本时,可将自定义用户名和密码验证程序与消息和传输安全一起使用。使用 .NET Framework 3.0 时,自定义用户名和密码验证程序只能与消息安全一起使用。 提示: 有关在此上下文中使用 <netTcpBinding> 的更多信息,请参见 <security> of <netTcpBinding>。 在配置文件中,在 <system.ServiceModel> 元素下面添加一个 <bindings> 元素。
向绑定节添加 wsHttpBinding Element 或 <basicHttpBinding> 元素。有关创建 WCF 绑定元素的更多信息,请参见如何:在配置中指定服务绑定。
将 security element of wsHttpBinding或 <security> of <basicHttpBinding> 的 mode 属性设置为 Message、Transport 或 TransportWithMessageCredential。
设置 message element of wsHttpBinding 或 <transport> of <wsHttpBinding> 的 clientCredentialType 属性。
使用消息安全时,将 message element of wsHttpBinding的 clientCredentialType 属性设置为 UserName。
在 HTTP(S) 上使用传输级安全时,将 <transport> of <wsHttpBinding> 或 <transport> of <basicHttpBinding> 的 clientCredentialType 属性设置为 Basic。
注意: 如果使用传输级安全在 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>
配置一个行为,该行为指定使用自定义用户名和密码验证程序来验证传入的 UserNameSecurityToken 安全令牌的用户名和密码对。
添加一个 <behaviors> 元素,将其作为 <system.serviceModel> 元素的子级。
向 <behaviors> 元素中添加一个 serviceBehaviors section。
添加一个 <behavior> 元素,并将 name 属性设置为适当的值。
向 <behavior> 元素中添加一个 <serviceCredentials> Element。
向 <serviceCredentials> Element中添加一个 userNameAuthentication element。
将 userNamePasswordValidationMode 设置为 Custom。
注意: 如果未设置 userNamePasswordValidationMode 值,WCF 会使用 Windows 身份验证而不是自定义用户名和密码验证程序。 将 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");
}
}
}