2011-10-01 130 views
2

问题:ASP.NET:为无Cookie会话实现ISessionIDManager?

我在写一个自定义会话提供程序。 到目前为止,它工作出色。 我决定我想添加一个自定义的ISessionIDManager来控制会话ID。

它已经正常工作的cookie会话。 但是,当我向SWICH cookie的,就像这样:

<sessionState mode="Custom" customProvider="custom_provider" cookieless="true" timeout="1" 
       sessionIDManagerType="Samples.AspNet.Session.MySessionIDManager" 
       sqlConnectionString="Data Source=localhost;Initial Catalog=TestDB;User Id=SomeUser;Password=SomePassword;" 
       sqlCommandTimeout="10" 
       > 
    <!-- timeout in minutes--> 
    <providers> 
     <add name="custom_provider" type="Test.WebSession.CustomSessionStoreProvider" /> 
    </providers> 
    </sessionState> 

然后重定向到:
http://localhost:52897/(77bb065f-d2e9-4cfc-8117-8b89a40e00d8)/default.aspx
,这将引发HTTP 404

我明白为什么,因为没有这样的文件夹。

但你使用默认的会话管理器(一个附带asp.net)时,并切换到无Cookie,网址如下:
http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx

并没有HTTP 404 ...

我试着添加(S和)到我的会话id在括号中的url,但是没有帮助。


我错过了什么?

using System; 
using System.Configuration; 
using System.Web.Configuration; 
using System.Web; 
using System.Web.SessionState; 

// http://allantech.blogspot.com/2011/04/cookieless-session-state-in-aspnet.html 
// http://forums.asp.net/t/1082784.aspx/1 

// http://stackoverflow.com/questions/4612310/implementing-a-custom-sessionidmanager 
// http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager.aspx 
// http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager(v=vs.80).aspx 

namespace Samples.AspNet.Session 
{ 

    // Samples.AspNet.Session.MySessionIDManager 
    public class MySessionIDManager : IHttpModule, ISessionIDManager 
    { 

     protected SessionStateSection pConfig = null; 
     internal const string HeaderName = "AspFilterSessionId"; 


     protected void InitializeModule() 
     { 
      // Obtain session-state configuration settings. 
      if (pConfig == null) 
      { 
       Configuration cfg = 
        WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath); 
       pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState"); 
      } // End if (pConfig == null) 
     } 

     // 
     // IHttpModule Members 
     // 


     // 
     // IHttpModule.Init 
     // 
     public void Init(HttpApplication app) 
     { 
      //InitializeModule(); 
     } // End Sub Init 


     // 
     // IHttpModule.Dispose 
     // 
     public void Dispose() 
     { 
     } // End Sub Dispose 




     // 
     // ISessionIDManager Members 
     // 




     // 
     // ISessionIDManager.Initialize 
     // 
     public void Initialize() 
     { 
      InitializeModule(); 
     } // End Sub Initialize 


     // 
     // ISessionIDManager.InitializeRequest 
     // 
     public bool InitializeRequest(
      HttpContext context, 
      bool suppressAutoDetectRedirect, 
      out bool supportSessionIDReissue 
     ) 
     { 

      if (pConfig.Cookieless == HttpCookieMode.UseCookies) 
      { 
       supportSessionIDReissue = false; 
       return false; 
      } 
      else 
      { 
       supportSessionIDReissue = true; 
       return context.Response.IsRequestBeingRedirected; 
      } 

     } // End Function InitializeRequest 





     // 
     // ISessionIDManager.GetSessionID 
     // 
     public string GetSessionID(HttpContext context) 
     { 
      string id = null; 

      if (pConfig.Cookieless == HttpCookieMode.UseUri) 
      { 
       string tmp = context.Request.Headers[HeaderName]; 
       if (tmp != null) 
        id = HttpUtility.UrlDecode(id); 

       // Retrieve the SessionID from the URI. 
      } 
      else 
      { 
       if (context.Request.Cookies.Count > 0) 
       { 
        id = context.Request.Cookies[pConfig.CookieName].Value; 
        id = HttpUtility.UrlDecode(id); 
       } 
      } 

      // Verify that the retrieved SessionID is valid. If not, return null. 

      if (!Validate(id)) 
       id = null; 

      return id; 
     } // End Function GetSessionID 


     // 
     // ISessionIDManager.CreateSessionID 
     // 
     public string CreateSessionID(HttpContext context) 
     { 
      return System.Guid.NewGuid().ToString(); 
     } // End Function CreateSessionID 


     // 
     // ISessionIDManager.RemoveSessionID 
     // 
     public void RemoveSessionID(HttpContext context) 
     { 
      context.Response.Cookies.Remove(pConfig.CookieName); 
     } // End Sub RemoveSessionID 



     public static string InsertSessionId(string id, string path) 
     { 
      string dir = GetDirectory(path); 
      if (!dir.EndsWith("/")) 
       dir += "/"; 

      string appvpath = HttpRuntime.AppDomainAppVirtualPath; 
      if (!appvpath.EndsWith("/")) 
       appvpath += "/"; 

      if (path.StartsWith(appvpath)) 
       path = path.Substring(appvpath.Length); 

      if (path[0] == '/') 
       path = path.Length > 1 ? path.Substring(1) : ""; 

      // //http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx 
      return Canonic(appvpath + "(" + id + ")/" + path); 
      //return Canonic(appvpath + "(S(" + id + "))/" + path); 
     } 


     public static bool IsRooted(string path) 
     { 
      if (path == null || path.Length == 0) 
       return true; 

      char c = path[0]; 
      if (c == '/' || c == '\\') 
       return true; 

      return false; 
     } 


     public static string Canonic(string path) 
     { 
      char[] path_sep = { '\\', '/' }; 


      bool isRooted = IsRooted(path); 
      bool endsWithSlash = path.EndsWith("/"); 
      string[] parts = path.Split(path_sep); 
      int end = parts.Length; 

      int dest = 0; 

      for (int i = 0; i < end; i++) 
      { 
       string current = parts[i]; 

       if (current.Length == 0) 
        continue; 

       if (current == ".") 
        continue; 

       if (current == "..") 
       { 
        dest--; 
        continue; 
       } 
       if (dest < 0) 
        if (!isRooted) 
         throw new HttpException("Invalid path."); 
        else 
         dest = 0; 

       parts[dest++] = current; 
      } 
      if (dest < 0) 
       throw new HttpException("Invalid path."); 

      if (dest == 0) 
       return "/"; 

      string str = String.Join("/", parts, 0, dest); 

      str = RemoveDoubleSlashes(str); 

      if (isRooted) 
       str = "/" + str; 
      if (endsWithSlash) 
       str = str + "/"; 

      return str; 
     } 




     public static string GetDirectory(string url) 
     { 
      url = url.Replace('\\', '/'); 
      int last = url.LastIndexOf('/'); 

      if (last > 0) 
      { 
       if (last < url.Length) 
        last++; 

       return RemoveDoubleSlashes(url.Substring(0, last)); 
      } 

      return "/"; 
     } 


     public static string RemoveDoubleSlashes (string input) 
     { 
      // MS VirtualPathUtility removes duplicate '/' 

      int index = -1; 
      for (int i = 1; i < input.Length; i++) 
      if (input [i] == '/' && input [i - 1] == '/') { 
       index = i - 1; 
       break; 
      } 

      if (index == -1) // common case optimization 
      return input; 

      System.Text.StringBuilder sb = new System.Text.StringBuilder(input.Length); 
      sb.Append (input, 0, index); 

      for (int i = index; i < input.Length; i++) { 
      if (input [i] == '/') { 
       int next = i + 1; 
       if (next < input.Length && input [next] == '/') 
       continue; 
       sb.Append ('/'); 
      } 
      else { 
       sb.Append (input [i]); 
      } 
      } 

      return sb.ToString(); 
     } 



     // http://www.dotnetfunda.com/articles/article1531-how-to-add-custom-headers-into-readonly-httprequest-object-using-httpmodule-.aspx 
     public void SetHeader(string strHeaderName, string strValue) 
     { 
      //get a reference 
      System.Collections.Specialized.NameValueCollection headers = HttpContext.Current.Request.Headers; 
      //get a type 
      Type t = headers.GetType(); 
      //get the property 
      System.Reflection.PropertyInfo prop = t.GetProperty(
        "IsReadOnly", 
        System.Reflection.BindingFlags.Instance 
       | System.Reflection.BindingFlags.IgnoreCase 
       | System.Reflection.BindingFlags.NonPublic 
       | System.Reflection.BindingFlags.FlattenHierarchy 
       | System.Reflection.BindingFlags.NonPublic 
       | System.Reflection.BindingFlags.Public 
       | System.Reflection.BindingFlags.FlattenHierarchy 
      ); 
      //unset readonly 

      prop.SetValue(headers, false, null); // Set Read-Only to false 

      //add a header 
      //HttpContext.Current.Request.Headers.Add(strHeaderName, strValue); 
      //headers.Add(strHeaderName, strValue); 

      t.InvokeMember("BaseAdd", 
        System.Reflection.BindingFlags.InvokeMethod 
       | System.Reflection.BindingFlags.NonPublic 
       | System.Reflection.BindingFlags.Instance, 
        null, 
        headers, 
        new object[] { strHeaderName, new System.Collections.ArrayList { strValue } } 
      ); 

      prop.SetValue(headers, true, null); // Reset Read-Only to true 

      // Victory ! 

      //string strCheckHeaders = string.Join(Environment.NewLine, HttpContext.Current.Request.Headers.AllKeys); 
     } 

     // 
     // ISessionIDManager.SaveSessionID 
     // 
     public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded) 
     { 
      if (!Validate(id)) 
       throw new HttpException("Invalid session ID"); 

      Type t = base.GetType(); 

      redirected = false; 
      cookieAdded = false; 

      if (pConfig.Cookieless == HttpCookieMode.UseUri) 
      { 
       // Add the SessionID to the URI. Set the redirected variable as appropriate. 

       //context.Request.Headers.Add(HeaderName, id); 
       //context.Request.Headers.Set(HeaderName, id); 
       SetHeader(HeaderName, id); 

       cookieAdded = false; 
       redirected = true; 
       UriBuilder newUri = new UriBuilder(context.Request.Url); 
       newUri.Path = InsertSessionId(id, context.Request.FilePath); 

       //http://localhost:52897/(S(sq2abm453wnasg45pvboee45))/DisplaySessionValues.aspx 
       context.Response.Redirect(newUri.Uri.PathAndQuery, false); 
       context.ApplicationInstance.CompleteRequest(); // Important ! 

       return; 
      } 
      else 
      { 
       context.Response.Cookies.Add(new HttpCookie(pConfig.CookieName, id)); 
       cookieAdded = true; 
      } 

     } // End Sub SaveSessionID 


     // 
     // ISessionIDManager.Validate 
     // 
     public bool Validate(string id) 
     { 
      try 
      { 
       Guid testGuid = new Guid(id); 

       if (id == testGuid.ToString()) 
        return true; 
      } 
      catch 
      { 
      } 

      return false; 
     } // End Function Validate 


    } // End Class MySessionIDManager : IHttpModule, ISessionIDManager 


} // End Namespace Samples.AspNet.Session 
+0

我正在尝试做一些类似于你。我想更改无Cookie模式取决于我的域名和IP(wap代理IP)。我完全失去了。你有更多的东西吗? thx提前 – fravelgue

回答

4

从头开始创建自定义会话ID管理器看起来很多工作。那么从System.Web.SessionState.SessionIDManager类继承并重写CreateSessionID方法呢?

public class MySessionIDManager : SessionIDManager, ISessionIDManager 
{ 
    public override string CreateSessionID(HttpContext context) 
    { 
     return System.Guid.NewGuid().ToString("N"); 
    } 
} 
+0

有趣。应该管用。这也需要覆盖验证,但这没有问题。 –

+0

@StefanSteiger你尝试过使用'SessionIDManager'类吗? – Kiquenet

0

当所有其他都失败时,用Reflector或ILSpy打开.NET实现,看看他们做的不同。

+0

他们没有实现ISessionIDManager,他们实现了一个HTTP模块。 –