zoukankan      html  css  js  c++  java
  • WCF 基于Cookie的登录验证回传问题的解决

      参考资料:

    http://www.cnblogs.com/czcz1024/p/3333138.html

    http://megakemp.com/2009/02/06/managing-shared-cookies-in-wcf/

    首先使用的绑定 必须允许Cookie传播

          <wsHttpBinding>
            <binding  closeTimeout="00:01:30" openTimeout="00:01:30"  maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
               transactionFlow="true" allowCookies="True">
              <reliableSession enabled="true" />
              
              <security mode= "None">
              </security>
            </binding>
          </wsHttpBinding>

    其次
    服务需要基于ASP.NET 的激活进行host
        <!--运行服务以ASP.NET激活模式激活服务-->
        <serviceHostingEnvironment aspNetCompatibilityEnabled ="true" multipleSiteBindingsEnabled="true" />

    第三 服务的实现 ,基于属性的声明允许以ASP.NET的方式访问
        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
        public class AddressWCFService : IAddressWCFService
    第四 最关键的一部,实现客户端的消息发送 响应拦截器
    	/// <summary>
    		/// Gets the singleton <see cref="ClientIdentityMessageInspector" /> instance.
    		/// </summary>
    		public static CookieManagerMessageInspector Instance
    		{
    			get
    			{
    				if (instance == null)
    				{
    					instance = new CookieManagerMessageInspector();
    				}
     
    				return instance;
    			}
    		}
     
    		/// <summary>
    		/// Inspects a message after a reply message is received but prior to passing it back to the client application.
    		/// </summary>
    		/// <param name="reply">The message to be transformed into types and handed back to the client application.</param>
    		/// <param name="correlationState">Correlation state data.</param>
    		public void AfterReceiveReply(ref Message reply, object correlationState)
    		{
    			HttpResponseMessageProperty httpResponse =
    				reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
     
    			if (httpResponse != null)
    			{
    				string cookie = httpResponse.Headers[HttpResponseHeader.SetCookie];
     
    				if (!string.IsNullOrEmpty(cookie))
    				{
    					this.sharedCookie = cookie;
    				}
    			}
    		}
     
    		/// <summary>
    		/// Inspects a message before a request message is sent to a service.
    		/// </summary>
    		/// <param name="request">The message to be sent to the service.</param>
    		/// <param name="channel">The client object channel.</param>
    		/// <returns>
    		/// <strong>Null</strong> since no message correlation is used.
    		/// </returns>
    		public object BeforeSendRequest(ref Message request, IClientChannel channel)
    		{
    			HttpRequestMessageProperty httpRequest;
     
    			// The HTTP request object is made available in the outgoing message only when
    			// the Visual Studio Debugger is attacched to the running process
    			if (!request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
    			{
    				request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
    			}
     
    			httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
    			httpRequest.Headers.Add(HttpRequestHeader.Cookie, this.sharedCookie);
     
    			return null;
    		}


    最后一步:为客户端的Behavior添加行为扩展
    	public class CookieManagerEndpointBehavior : IEndpointBehavior
    	{
    		public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    		{
    			return;
    		}
     
    
    		public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    		{
    			clientRuntime.MessageInspectors.Add(CookieManagerMessageInspector.Instance);
    		}
     
    		public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    		{
    			return;
    		}
     
    		public void Validate(ServiceEndpoint endpoint)
    		{
    			return;
    		}
    	}
    到此 就可以配置客户端ClientProxy代理的实例 进行Cookie的传播共享了。下面是客户端的Behavior的扩展
        <behaviors>
          <endpointBehaviors>
            <behavior name="CookieBehaviorConfig">
               <clear/>
              <!--注册行为扩展-->
              <CookieBehavior />
            </behavior>
          </endpointBehaviors>
        </behaviors>
        
        <!--扩展 客户端的Behavior-->
        <extensions>
          <behaviorExtensions>
            <add name="CookieBehavior" type="Smart.Client.CookieManager.CookieManagerBehaviorExtension, Smart.Client.CookieManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </behaviorExtensions>
        </extensions>

    以下是作者原文,本文基于作者思路而来,谢谢。

    wcf读写cookie

     

    一般来说,web应用的服务端(aspx或mvc的action)调用wcf时,是一个服务与服务的通讯,而不是客户端(浏览器)与服务器的通讯。

    这种情况下,如果要在wcf端处理客户端的cookie,就需要做一些额外的开发。

    首先,在wcf的web.config里,需要启用

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

    之后,wcf的实现类需要加attribute

    [AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]

    做完上面的两步,在wcf具体的方法里就可以使用HttpContext.Current .Resposne/.Request来读写cookie了。

    但是,正如上面所说,这是一个服务器与服务器的通讯,客户端(web应用)并不会自动发送cookie到wcf。所以客户端还得做更多的工作

    核心在IClientMessageInspector 这个接口,他有

    BeforeSendRequest和AfterReceiveReply两个方法。

    我们的目的是在beforeSendRequest时,在请求中加入cookie信息,在AfterReciveReply方法中,从响应中获取要设置的cookie,并真正设置到客户端(浏览器)

    public class CookieMessageInspector : IClientMessageInspector
    新建一个类,来实现接口
       1: public object BeforeSendRequest(ref Message request,System.ServiceModel.IClientChannel channel)
       2: {
       3:     var cookie = GetCookieValue();
       4:  
       5:     HttpRequestMessageProperty httpRequestMessage;
       6:     object httpRequestMessageObject;
       7:  
       8:     if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
       9:     {
      10:         httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
      11:         if (string.IsNullOrEmpty(httpRequestMessage.Headers["Cookie"]))
      12:         {
      13:             httpRequestMessage.Headers["Cookie"] = cookie;
      14:         }
      15:     }
      16:     else
      17:     {
      18:         httpRequestMessage = new HttpRequestMessageProperty();
      19:         httpRequestMessage.Headers.Add("Cookie", cookie);
      20:         request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
      21:     }
      22:  
      23:     return null;
      24: }

    我们需要把cookie值,转化成字符串进行传递,cookie名=cookie值这样的形式,多个cookie用分号(;)分隔。

    我们新建的这个类,要如何使用呢,他需要在一个behavior中调用。所以我们还得建立一个behavior

    public class CookieBehavior : IEndpointBehavior

    实现接口IEndpointBehavior,并且在方法ApplyClientBehavior中加入我们刚才的类

    public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint,ClientRuntime behavior)
    {
        behavior.MessageInspectors.Add(new CookieMessageInspector());
    }

    其他需要实现的方法,直接return即可

    通过vs添加服务引用,他会自动生成一个代理类。在new这个代理类之后,加入我们新建的behavior

    var client = new TestSvc.TestSvcClient();
    CookieBehavior b = new CookieBehavior();
    client.Endpoint.Behaviors.Add(b);

    之后,我们调用方法,就会把cookie信息传递到wcf了。

    到目前为止,我们可以解决web向wcf传递当前cookie,wcf可以读取cookie。

    下面我们解决在wcf中设置cookie。

    同样的原理,在读取的时候,我们是在BeforeSendRequest中实现的,那写入则需要在AfterReceiveReply中实现了。

    在wcf中使用

    HttpContext.Current.Response.Cookies.Add(new HttpCookie("test123", "123"));

    类似这样的代码设置cookie,他在响应的header里会有Set-Cookie,我们只需要处理Set-Cookie里面的内容就可以了。

    在写入多个cookie时,与读操作不同,这里是用逗号(,)分隔的,并且默认他会带cookie的path,如果你设置了cookie的domain,过期时间等,他也会传递,并且同一个cookie的若干属性之间是用分号(;)分隔的

       1: public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply,object correlationState)
       2: {
       3:     if (reply.Properties.ContainsKey("httpResponse"))
       4:     {
       5:         HttpResponseMessageProperty httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
       6:  
       7:         if (httpResponse != null)
       8:         {
       9:             string cookie = httpResponse.Headers.Get("Set-Cookie");
      10:             if (!string.IsNullOrEmpty(cookie))
      11:             {
      12:                 //解析并设置cookie
      13:             }
      14:         }
      15:     }
      16: }

    具体如何解析,就是字符串操作,就不细说了。

    以上方式可以实现web应用的服务器端与wcf通讯时,附带客户端(浏览器)的cookie信息,进行读写操作。

    但是每次都需要对client进行设置,相对比较麻烦。我们可以通过web.config中的配置来让client自动加入behavior。

    同样,我们需要下面这样的一个类

    public class CookieBehaviorExtensionElement :BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new CookieBehavior();
        }
    
        public override Type BehaviorType
        {
            get { return typeof(CookieBehavior); }
        }
    }

    之后,在web项目的web.config中

    <system.serviceModel>

    此节点下,首先需要加入

    <extensions>
      <behaviorExtensions>
        <add name="CookieBehavior" type="webhost.CookieBehaviorExtensionElement, webhost, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
    注意type是的写法,需要根据自己项目的命名空间来进行修改
    之后
    <behaviors>
      <endpointBehaviors>
        <behavior name="CookieBehaviorConfig">
          <CookieBehavior />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    
    
    黄色部分,为extensions中我们添加的那条的name
    最后
    <endpoint address="http://localhost:5351/testSvc.svc" binding="basicHttpBinding"
            bindingConfiguration="BasicHttpBinding_ITestSvc" contract="TestSvc.ITestSvc"
            name="BasicHttpBinding_ITestSvc" behaviorConfiguration="CookieBehaviorConfig" />
    
    
    设置endpoint的behaviorConfiguration为behaviors节中添加的behavior的name
    
    
     
    
    
    如此,我们就可以不用每次new client之后在去设置它的behavior了
    
    
  • 相关阅读:
    msp430入门学习43
    msp430入门学习42
    msp430入门学习41
    msp430入门学习40
    msp430入门学习37
    msp430入门学习36
    msp430入门学习35
    JAVA三大特性之三——多态
    JAVA三大特性之二——继承
    JAVA三大特性之一——封装
  • 原文地址:https://www.cnblogs.com/micro-chen/p/4133166.html
Copyright © 2011-2022 走看看