WCF安全:通过 扩展实现用户名密码认证
在webSservice时代,可以通过SOAPHEADER的方式很容易将用户名、密码附加到SOAP header消息头上,用户客户端对调用客户端身份的验证。在WCF 时代,也可以通过OperationContext.Current.IncomingMessageHeaders的方式将用户名、密码附加到SOAP消息中。但是这种方式实现起来有个缺点;那就是所有调用客户端都需要这样做才能将我们需要通过认证的帐号、密码附加到SOAP消息上。实际上,也可以通过WCF扩展的方式,在客户端自动将用户名、密码附加到SOAP消息中。这即是本文主题。
1、客户端消息自动附加用户名、密码
实现IClientMessageInspector接口,用于附加调用者的账号、密码信息
public class ClientMessageInspector : IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { } public object BeforeSendRequest(ref Message request, IClientChannel channel) { MessageHeader userNameHeader = MessageHeader.CreateHeader("OperationUserName", "http://tempuri.org", "account", false, ""); MessageHeader pwdNameHeader = MessageHeader.CreateHeader("OperationPwd", "http://tempuri.org", "password", false, ""); request.Headers.Add(userNameHeader); request.Headers.Add(pwdNameHeader); Console.WriteLine(request); return null; } }
2、实现IEndpointBehavior 接口。用户将客户端的消息检查器添加到clientruntime的消息检查器集合中.注意,以下代码中为了简单将服务端分发消息检查器也添加到服务端终结点分发器(EndpointDispatcher)的分发运行时的消息检查器中。
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new ClientMessageInspector());//客户端使用 } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MessageDispatcher());//服务端使用 } public void Validate(ServiceEndpoint endpoint) { }
3、实现抽象类BehaviorextensionElement.用于在配置文件中配置对WCF服务行为的扩展
internal class MessageBindingElement : BehaviorExtensionElement { public override Type BehaviorType { get { return typeof (MessageEndpointBehavior); } } protected override object CreateBehavior() { return new MessageEndpointBehavior(); } }
4、服务端验证客户端的账号、密码
实现IDispatcherMessageInspector
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { Console.WriteLine(request); string userName = GetHeaderValue("OperationUserName"); string pwd = GetHeaderValue("OperationPwd"); if ("account" == userName && "password" == pwd) { return null; } throw new Exception("用户名、密码错误"); } public void BeforeSendReply(ref Message reply, object correlationState) { } string GetHeaderValue(string key) { int index = OperationContext.Current.IncomingMessageHeaders.FindHeader(key, "http://tempuri.org"); if (index >= 0) { return OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(index).ToString(); } return null; }
5、服务端配置;
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <extensions> <behaviorExtensions> <add name="messageInterptor" type="MessageInterceptor.MessageBindingElement,MessageInterceptor"/> </behaviorExtensions> </extensions> <behaviors> <endpointBehaviors> <behavior name="messageBehavior"> <messageInterptor /> </behavior> </endpointBehaviors> </behaviors> <services> <service name="Services.CalculatorService"> <endpoint address="net.tcp://127.0.0.1:8081/CalculateService" binding="netTcpBinding" contract="Contracts.ICalculator" behaviorConfiguration="messageBehavior"></endpoint> </service> </services> </system.serviceModel> </configuration>
6、客户端配置;
<?xml version="1.0"?> <configuration> <system.serviceModel> <client> <endpoint name="calculatorService" address="net.tcp://127.0.0.1:8081/CalculateService" binding="netTcpBinding" contract="Contracts.ICalculator" behaviorConfiguration="messageBehavior"> </endpoint> </client> <extensions> <behaviorExtensions> <add name="messageInterptor" type="MessageInterceptor.MessageBindingElement,MessageInterceptor"/> </behaviorExtensions> </extensions> <behaviors> <endpointBehaviors> <behavior name="messageBehavior"> <messageInterptor /> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
7、运行结果图;
服务端;
客户端;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构