WCF 和身份验证
Posted
技术标签:
【中文标题】WCF 和身份验证【英文标题】:WCF and Authentication 【发布时间】:2011-04-07 05:04:12 【问题描述】:每次向 WCF 发送请求时,我都需要从客户端传递一个值,并在服务器上检查该值并决定是否发出请求,任何人都可以写一个例子吗?我不知道会怎样实施
案例: 我根据客户端的硬件生成一个密钥,我想将该密钥与每个请求一起发送到服务器,以检查该密钥是否在服务器数据库中被接受,然后决定是否处理该请求。
提前致谢。
【问题讨论】:
请参阅***.com/questions/964433/… 以自动将数据作为标头传递。不过,我不知道如何在服务器上自动检查它,但我希望有一个钩子。 【参考方案1】:您正在寻找消息检查员。检查此article。
编辑:
在您的情况下,提到的方法是最简单的方法。您将创建客户端消息检查器以添加自定义标头和调度消息检查器以提取标头和验证密钥。如果密钥无效,您将抛出异常。
干净的解决方案是创建custom token 和cutom credentials,但这确实很复杂,因此除非您想深入了解 WCF 安全实现,否则请使用消息检查器。
【讨论】:
我根据客户端的硬件生成一个密钥,我想将该密钥与每个请求一起发送到服务器,以检查该密钥是否在服务器数据库中被接受,然后决定处理该请求与否 那么是身份验证(只是检查有密钥的客户端可以访问服务)还是授权(不同的密钥可以使用不同的操作集)? 只检查有密钥的客户端是否可以访问服务【参考方案2】:我已经实现了类似的东西来处理一些特别“自定义”的身份验证,其中根据数据库状态允许或拒绝方法。它使用 PerSession 实现,它允许您避免每次都传递该密钥,因为您可以在执行期间维护代理。它还通过消除重复实例化代理的开销来提供一些性能优势(根据您的设计,这可能不是问题)。
-
使用“PerSession”的 InstanceContextMode 实现您的服务
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
在您的服务中提供一个初始化方法,该方法接受密钥并保留对它的引用。
在您的服务方法中,检查该密钥、其他条件等以确定您需要做什么。
现在,当您实例化客户端代理时,首先调用该初始化方法并传递密钥,然后您可以继续在没有它的情况下进行调用。
【讨论】:
其实我已经实现了,非常感谢您的帮助,我使用了不同的方法我会尽快发布答案【参考方案3】:首先我们需要在客户端实现 Behavior 和 inspector 来发送 Key 来验证客户端:
class AuthenticationBehaviour : IEndpointBehavior
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
clientRuntime.MessageInspectors.Add(inspector);
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
//AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
//endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
public void Validate(ServiceEndpoint endpoint)
class AuthenticationMessageInspector : IClientMessageInspector
private const string HeaderKey = "Authentication";
public object BeforeSendRequest(ref Message request, IClientChannel channel)
if (Session.MachineId == 0)
Session.MachineId = LicenseGenerator.GenerateLicense();
request.Headers.Add(MessageHeader.CreateHeader(HeaderKey, string.Empty, Session.MachineId));
return null;
public void AfterReceiveReply(ref Message reply, object correlationState)
现在我们需要在服务器端(WCF 服务)实现 Behavior 和检查器来检查发出的每个请求并提取标头然后验证它:
public class AuthenticationBehaviour : IEndpointBehavior
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
//AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
//clientRuntime.MessageInspectors.Add(inspector);
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
AuthenticationMessageInspector inspector = new AuthenticationMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
//Console.WriteLine("Dispatcher Applied!");
public void Validate(ServiceEndpoint endpoint)
#endregion
public class AuthenticationMessageInspector : IDispatchMessageInspector
#region Members
private string conStr = "", commStr = "";
public IDbConnection Connection get; set;
public IDbCommand Command get; set;
public IDataReader Reader get; set;
#endregion
private const string HeaderKey = "Authentication";
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
//Console.WriteLine("recieved Request! ");
int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty);
if (headerIndex < 0 || string.IsNullOrEmpty(request.Headers.GetHeader<String>(headerIndex)))
throw (new Exception("Access Denied!\n"));
return null;
bool valid = Validate(request.Headers.GetHeader<String>(headerIndex));
if (!valid)
Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex) + " and Access Denied!\n");
throw (new Exception("Access Denied!\n" + request.Headers.GetHeader<String>(headerIndex) + " License Number is not athourized! "));
if (headerIndex != -1)
Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex));
return null;
public void BeforeSendReply(ref Message reply, object correlationState)
现在让我们注册行为:
_routingHost.Description.Endpoints[0].Behaviors.Add(new Gateway.Controllers.AuthenticationBehaviour());
_routingHost.Open();
就是这样,谢谢。
【讨论】:
【参考方案4】:我在尝试在 WCF Rest 服务上实现身份验证机制时来到这篇文章,我试图在自定义消息检查器方法 AfterReceiveRequest 上获取身份验证标头,但在使用提供的 System.ServiceModel.Channel 检索标头时遇到问题.Message 对象(方法签名上的请求变量)
public object AfterReceiveRequest(ref Message request, IClientChannel channel,
InstanceContext instanceContext)
Dim headerIndex = request.Headers.FindHeader(HeaderKey, String.Empty)
headerIndex 将始终为 -1,因为我对此进行了研究并发现 Message 类有一个扩展方法,该方法允许将 Message 转换为 System.Net.Http.HttpRequestMessage 类型的对象。为此,只需导入以下程序集:System.ServiceModel.Channel、System.Net.Http。
Dim httpReq As System.Net.Http.HttpRequestMessage = request.ToHttpRequestMessage()
Dim authValue As String
If httpReq.Headers.Contains(HeaderKey) Then
authValue = httpReq.Headers.GetValues(HeaderKey)(0)
End If
【讨论】:
以上是关于WCF 和身份验证的主要内容,如果未能解决你的问题,请参考以下文章