WCF 学习总结5 -- 消息拦截实现用户名验证(转)

WCF创建在基于消息的通讯这一律念基础上。经过方法调用(Method Call)形式体现的服务访问须要转化成具体的消息,并经过相应的编码(Encoding)才能经过传输通道发送到服务端;服务操做执行的结果也只能以消息的形式才能被正常地返回到客户端。因此,消息在整个WCF体系结构中处于一个核心的地位,WCF能够当作是一个消息处理的管道,以下图所示: 
11_133734_wcf_architecture  
WCF的一个操做(以及操做的参数)被序列化为Soap协议所支持的消息(XML结构),通过服务运行层,交给Binding中所定义的消息传递层,消息传递层由通道(Channel)组成。通道是以某种方式对消息进行处理(例如经过对消息进行身份验证)的组件,通道对消息和消息头进行操做,而服务运行层主要针对消息正文内容进行处理。 
IC5864  

方法一. 经过OperationContext直接添加/访问MessageHeader信息 
使用OperationContext咱们能够:访问当前操做执行环境。 特别是,操做上下文用于访问双工服务中的回调通道、存储整个操做部分的额外状态数据、访问传入消息头和属性以及添加传出消息头和属性。下面用代码演示下如何在MessageHeader中添加额外的信息,进行用户验证。 
1. 服务契约 ide

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.Runtime.Serialization;  
  3. using System.ServiceModel;  
  4. namespace WcfSvcLib  
  5. {  
  6.     [ServiceContract(Namespace="http://blog.csdn.net/fangxinggood")]  
  7.     public interface IService1  
  8.     {  
  9.         [OperationContract]  
  10.         string GetData(int value);  
  11.     }  
  12. }  


2. 服务实现 编码

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.Runtime.Serialization;  
  3. using System.ServiceModel;  
  4. namespace WcfSvcLib  
  5. {  
  6.     public class Service1 : IService1  
  7.     {  
  8.         public string GetData(int value)  
  9.         {  
  10.             Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage);  
  11.             // 注意namespace必须和ServiceContract中定义的namespace保持一致,默认是:http://tempuri.org  
  12.             var ns = "http://blog.csdn.net/fangxinggood";  
  13.             var user = GetHeaderValue("user", ns);  
  14.             var pwd = GetHeaderValue("pwd", ns);  
  15.             // 验证失败会抛出Invalid User的异常。  
  16.             if (user != "fangxing" || pwd != "password")  
  17.                 throw new FaultException("Invalid User!");  
  18.             return string.Format("You entered: {0}", value);  
  19.         }  
  20.         private string GetHeaderValue(string name, string ns = "http://tempuri.org")  
  21.         {  
  22.             var headers = OperationContext.Current.IncomingMessageHeaders;  
  23.             var index = headers.FindHeader(name, ns);  
  24.             if (index > -1)  
  25.                 return headers.GetHeader<string>(index);  
  26.             else  
  27.                 return null;  
  28.         }  
  29.     }  
  30. }  


3. 客户端实现 spa

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.ServiceModel;  
  3. using System.ServiceModel.Channels;  
  4. namespace WcfClient  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             var client = new WcfSvc.Service1Client();  
  11.             using (var scope = new OperationContextScope(client.InnerChannel))  
  12.             {  
  13.                 // 注意namespace必须和ServiceContract中定义的namespace保持一致,默认是:http://tempuri.org  
  14.                 var myNamespace = "http://blog.csdn.net/fangxinggood";  
  15.                 // 注意Header的名字中不能出现空格,由于要做为Xml节点名。  
  16.                 var user = MessageHeader.CreateHeader("user", myNamespace, "fangxing");  
  17.                 var pwd = MessageHeader.CreateHeader("pwd", myNamespace, "password");  
  18.                 OperationContext.Current.OutgoingMessageHeaders.Add(user);  
  19.                 OperationContext.Current.OutgoingMessageHeaders.Add(pwd);  
  20.                 var result = client.GetData(100);  
  21.                 Console.WriteLine(result);  
  22.                 Console.Read();  
  23.             }  
  24.         }  
  25.     }  
  26. }  


运行一下,在服务端经过 Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage); 输出了请求的Message。经过输出的信息,咱们能够看到Header里添加的信息: 
simpleSoapHeaderMessage 

经过上面的代码,咱们能够完成相似WebService的SoapHeader验证。可是这样须要咱们每一个契约都作相似的添加、验证,这样岂不是很繁琐。下面看方法二,经过消息检查器完成统一的用户验证。 

方法二. 消息检查器方式添加/访问MessageHeader信息 
客户端经过实现IClientMessageInspector接口,服务端经过实现IDispatchMessageInspector接口,来拦截消息。这种方式是经过扩展Behavior来加入拦截的,因此还须要分别实现IEndpointBehavior(客户端)和IServiceBehavior(服务端)接口,并经过配置将消息检查器加入。 
工程结构: 
 messageInterpectorProjects 实现说明: 
【客户端】
 
1. ClientInterpector 实现: .net

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.ServiceModel.Dispatcher;  
  3. using System.ServiceModel.Configuration;  
  4. using System.ServiceModel.Channels;  
  5. using System.ServiceModel;  
  6. namespace WcfClientInterpector  
  7. {  
  8.     public class ClientInterpector : IClientMessageInspector  
  9.     {  
  10.         public void AfterReceiveReply(ref Message reply, object correlationState)  
  11.         {  
  12.         }  
  13.         public object BeforeSendRequest(ref Message request, IClientChannel channel)  
  14.         {  
  15.             var userNameHeader = MessageHeader.CreateHeader("OperationUserName""http://tempuri.org""fangxing"false"");  
  16.             var pwdNameHeader = MessageHeader.CreateHeader("OperationPwd""http://tempuri.org""password"false"");  
  17.             request.Headers.Add(userNameHeader);  
  18.             request.Headers.Add(pwdNameHeader);  
  19.             Console.WriteLine(request);  
  20.             return null;  
  21.         }  
  22.     }  
  23. }  


2. MyClientBehavior 实现: (实现扩展endpointBehavior元素) orm

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.ServiceModel.Configuration;  
  3. using System.ServiceModel.Description;  
  4. using System.ServiceModel.Dispatcher;  
  5. using System.ServiceModel;  
  6. namespace WcfClientInterpector  
  7. {  
  8.     public class MyClientBehavior : BehaviorExtensionElement, IEndpointBehavior  
  9.     {  
  10.         public override Type BehaviorType  
  11.         {  
  12.             get { return typeof(MyClientBehavior); }  
  13.         }  
  14.         protected override object CreateBehavior()  
  15.         {  
  16.             return new MyClientBehavior();  
  17.         }  
  18.         #region IEndpointBehavior Members  
  19.         public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)  
  20.         {  
  21.         }  
  22.         public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)  
  23.         {  
  24.             clientRuntime.MessageInspectors.Add(new ClientInterpector());  
  25.         }  
  26.         public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)  
  27.         {  
  28.         }  
  29.         public void Validate(ServiceEndpoint endpoint)  
  30.         {  
  31.         }  
  32.         #endregion  
  33.     }  
  34. }  


3. 配置 
修改客户端配置文件,步骤以下: 
(1) 在Advanced>Extensions>behavior element extensions中加入自定义的ClientInterpector。 
clientInterpectorConfig1  
(2) 在Advanced>Endpoint Behaviors中定义一个Behavior,添加上面配置过的extension 
clientInterpectorConfig2  
(3) 修改Client>Endpoints下的Endpoint的Behavior Config指向(2)配置的Behavior。 
clientInterpectorConfig3 

【服务端】 
1. ServiceInterpector 实现: server

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.ServiceModel.Dispatcher;  
  3. using System.ServiceModel;  
  4. namespace WcfServiceInterpector  
  5. {  
  6.     public class ServiceInterpector : IDispatchMessageInspector  
  7.     {  
  8.         #region IDispatchMessageInspector Members  
  9.         public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)  
  10.         {  
  11.             Console.WriteLine(request);  
  12.             var user = GetHeaderValue("OperationUserName");  
  13.             var pwd = GetHeaderValue("OperationPwd");  
  14.             if (user != "fangxing" || pwd != "password")  
  15.                 throw new FaultException("Invalid User!");  
  16.             return null;  
  17.         }  
  18.         public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)  
  19.         {  
  20.         }  
  21.         private string GetHeaderValue(string name, string ns = "http://tempuri.org")  
  22.         {  
  23.             var headers = OperationContext.Current.IncomingMessageHeaders;  
  24.             var index = headers.FindHeader(name, ns);  
  25.             if (index > -1)  
  26.                 return headers.GetHeader<string>(index);  
  27.             else  
  28.                 return null;  
  29.         }  
  30.         #endregion  
  31.     }  
  32. }  


2. MyServiceBehavior 实现:(实现扩展serviceBehavior元素) blog

[c-sharp]  view plain copy
 
  1. using System;  
  2. using System.ServiceModel.Configuration;  
  3. using System.ServiceModel.Description;  
  4. using System.ServiceModel.Dispatcher;  
  5. namespace WcfServiceInterpector  
  6. {  
  7.     public class MyServiceBehavior : BehaviorExtensionElement, IServiceBehavior  
  8.     {  
  9.         public override Type BehaviorType  
  10.         {  
  11.             get { return typeof(MyServiceBehavior); }  
  12.         }  
  13.         protected override object CreateBehavior()  
  14.         {  
  15.             return new MyServiceBehavior();  
  16.         }  
  17.         #region IServiceBehavior Members  
  18.         public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)  
  19.         {  
  20.         }  
  21.         public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)  
  22.         {  
  23.             foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers)  
  24.             {  
  25.                 foreach (EndpointDispatcher epDisp in chDisp.Endpoints)  
  26.                 {  
  27.                     epDisp.DispatchRuntime.MessageInspectors.Add(new ServiceInterpector());  
  28.                 }  
  29.             }  
  30.         }  
  31.         public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)  
  32.         {  
  33.         }  
  34.         #endregion  
  35.     }  
  36. }  


3. 配置 
修改服务端配置文件,步骤以下: 
(1) 在Advanced>Extensions>behavior element extensions中加入自定义的ServiceInterpector。 
serverInterpectorConfig1  
(2) 在Advanced>Service Behaviors中定义一个Behavior,添加上面配置过的extension 
serverInterpectorConfig2  
(3) 修改Services下的服务节点的Behavior Config指向(2)配置的Behavior。 
serverInterpectorConfig3  接口

相关文章
相关标签/搜索