如何:使用自定义用户名和密码验证程序
默认情况下,将用户名和密码用于身份验证时,Windows Communication Foundation (WCF) 会使用 Windows 来验证用户名和密码。 不过,WCF 允许自定义用户名和密码身份验证方案,也称为“验证程序”。 若要合并自定义用户名和密码验证程序,请创建一个从 UserNamePasswordValidator 派生的类,然后对其进行配置。
有关示例应用程序,请参阅用户名密码验证程序。
创建自定义用户名和密码验证程序
创建一个从 UserNamePasswordValidator 派生的类。
public class CustomUserNameValidator : UserNamePasswordValidator {
Public Class CustomUserNameValidator Inherits UserNamePasswordValidator
通过重写 Validate 方法,实现自定义身份验证方案。
请不要使用下面示例中的代码在生产环境中重写 Validate 方法。 请将该代码替换为你的自定义用户名和密码验证方案,这可能会涉及到从数据库检索用户名和密码对。
若要将身份验证错误返回到客户端,应在 FaultException 方法中引发 Validate。
// 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 informative fault to the client, // throw the following exception. // throw new SecurityTokenException("Unknown Username or Incorrect Password"); } }
' 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 = "[PLACEHOLDER]") AndAlso Not (userName = "test2" AndAlso password = "[PLACEHOLDER]") 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 informative fault to the client, ' throw the following exception: ' Throw New SecurityTokenException("Unknown Username or Incorrect Password") End If End Sub
配置服务以使用自定义用户名和密码验证程序
配置一个绑定,该绑定在任何传输上使用消息安全,或者在 HTTP(S) 上使用传输级安全。
使用消息安全性时,请添加系统提供的绑定之一,例如 <wsHttpBinding>,或支持消息安全性和
UserName
凭据类型的 <customBinding>。在通过 HTTP(S) 使用传输级安全性时,请添加 <wsHttpBinding> 或 <basicHttpBinding>,或者添加 <netTcpBinding> 或使用 HTTP(S) 和
Basic
身份验证方案的 <customBinding>。备注
使用 .NET Framework 3.5 或更高版本时,可将自定义用户名和密码验证程序与消息和传输安全性一起使用。 使用 WinFX 时,自定义用户名和密码验证程序只能与消息安全性一起使用。
提示
有关在此上下文中使用 <netTcpBinding> 的详细信息,请参阅 <security>。
在配置文件中,在 <system.serviceModel> 元素下添加一个 <bindings> 元素。
将 <wsHttpBinding> 或 <basicHttpBinding> 元素添加到 bindings 节。 有关创建 WCF 绑定元素的详细信息,请参阅如何:在配置中指定服务绑定。
将 <security> 的
mode
属性或 <security> 设置为Message
、Transport
或TransportWithMessageCredential
。设置 <message> 或 <transport> 的
clientCredentialType
属性。使用消息安全性时,请将 <message> 的
clientCredentialType
属性设置为UserName
。通过 HTTP(S) 使用传输级安全性时,请将 <transport> 的
clientCredentialType
属性或 <transport> 设置为Basic
。备注
如果使用传输级安全在 Internet Information Services (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> 元素的子级。
将 <serviceBehaviors> 添加到 <behaviors> 元素。
添加一个 <behavior> 元素,并将
name
特性设置为适当的值。将 <serviceCredentials> 添加到 <behavior> 元素。
将
userNamePasswordValidationMode
设置为Custom
。重要
如果未设置
userNamePasswordValidationMode
值,WCF 将使用 Windows 身份验证而不是自定义用户名和密码验证程序。将
customUserNamePasswordValidatorType
设置为表示自定义用户名和密码验证程序的类型。
以下示例演示到目前为止的
<serviceCredentials>
片段:<serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.ServiceModel.Samples.CalculatorService.CustomUserNameValidator, service" /> </serviceCredentials>
示例
下面的代码示例演示如何创建自定义用户名和密码验证程序。 请不要使用代码重写生产环境中的 Validate 方法。 请将该代码替换为你的自定义用户名和密码验证方案,这可能会涉及到从数据库检索用户名和密码对。
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Principal;
using System.ServiceModel;
Imports System.IdentityModel.Selectors
Imports System.IdentityModel.Tokens
Imports System.Security.Principal
Imports 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 informative fault to the client,
// throw the following exception.
// throw new SecurityTokenException("Unknown Username or Incorrect Password");
}
}
}
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 = "[PLACEHOLDER]") AndAlso Not (userName = "test2" AndAlso password = "[PLACEHOLDER]") 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 informative fault to the client,
' throw the following exception:
' Throw New SecurityTokenException("Unknown Username or Incorrect Password")
End If
End Sub
End Class