2015-05-29 15 views
4

我们有一个非常大的网页应用程序,有很多页面。这些页面要求我们了解用户的角色以正确显示内容。所以在Application_AuthenticationRequest,我们有这样的代码:如何持久化Application_AuthenticateRequest中所需的会话特定值?

var id = new GenericIdentity(Request.Headers["ceid"]); 
var rp = new MyRoleProvider(); 
var principal = new GenericPrincipal(id, rp.GetRolesForUser(id.Name)); 
Context.User = principal; 

的问题是,我们需要使用Web服务来获取角色,并因为呼叫正在尽一切每次用户访问一个页面时,网页服务正遭受太多次打击。

理想的解决办法是,如果我们可以在角色存储在一个会话变量,不过,会议没有Application_AuthenticateRequest可用。我们考虑在应用程序变量中存储一个包含所有用户条目的字典,但我希望能找到更好的解决方案。

有没有我们可以存储在这样一种方式,他们将可里面Application_AuthenticationRequest当前用户的角色什么办法?我们非常安全,一个cookie是否是一个有效的选择?

+2

您是否知道有外的即用功能,以“缓存”用户的角色在cookie ? https://msdn.microsoft.com/en-us/library/system.web.security.roles.cacherolesincookie%28v=vs.110%29.aspx –

+0

如果你想使用Roles API,很多人都是自己的角色,因此存储在具有HttpOnly(仅在服务器上可用)设置为true的cookie是一个很好的解决方案。 –

+0

如果您不喜欢使用cookie,可能是[MemoryCache](https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache%28v=vs.110%29.aspx)是可能的解决方案? –

回答

1

我想创建一个静态类来保存我们的当前所有用户(基本上扩展你的字典的想法)的角色列表:如果给定ID的角色都没有出现在列表中,我们从Web服务进行检索。否则,我们返回存储的角色。

我们需要的手段一定量的用户不活动后过期数据(我们不希望继续对所有用户的所有角色在内存中的所有次),所以我们将实现我们自己的到期机制(20分钟,我的例)。

这是我会怎么写的课,我会怎么使用它:

/// <summary> 
    /// This is the static class that will hold the roles for all active users (active users 
    /// are those that have been using the website within the last 20 minutes). 
    /// </summary> 
    public static class MyRoles 
    { 
     /// <summary> 
     /// This class holds your roles 
     /// </summary> 
     private class Principal 
     { 
      private DateTime lastAccess; // Our expiration timer 
      private System.Security.Principal.GenericPrincipal principal; // Our roles 

      public Principal(System.Security.Principal.GenericPrincipal principal) 
      { 
       this.principal = principal; 
       this.lastAccess = DateTime.Now; 
      } 

      public System.Security.Principal.GenericPrincipal GenericPrincipal 
      { 
       get 
       { 
        // We reset our timer. It will expire 20 minutes from now. 
        this.lastAccess = DateTime.Now; 

        return principal; 
       } 
      }         

      /// <summary> 
      /// This tells us if a user has been active in the last 20 minutes 
      /// </summary> 
      public bool IsValid 
      { 
       get 
       { 
        // Valid within 20 minutes from last call 
        return DateTime.Now <= this.lastAccess.AddMinutes(20);       
       } 
      } 
     } 

     /// <summary> 
     /// This will hold IDs and related roles 
     /// </summary> 
     private static Dictionary<string, Principal> ids = new Dictionary<string, Principal>(); 

     /// <summary> 
     /// Method to retrieve roles for a given ID 
     /// </summary> 
     /// <param name="header">Our ID</param> 
     /// <returns></returns> 
     public static System.Security.Principal.GenericPrincipal GetRoles(string header) 
     { 
      if (ids.ContainsKey(header) && ids[header].IsValid) 
      { 
       // We have roles for this ID 
       return ids[header].GenericPrincipal; 
      } 
      else 
      { 
       // We don't have this ID (or it's expired) so get it from the web service 
       var id = new System.Security.Principal.GenericIdentity(header); 
       var principal = new System.Security.Principal.GenericPrincipal(id, new MyRoleProvider().GetRolesForUser(id.Name)); 

       // Store roles 
       ids.Add(header, new Principal(principal)); 

       return principal; 
      } 
     }    
    } 

    protected void Application_AuthenticateRequest(object sender, EventArgs e) 
    { 
     // This is how we use our class 
     var principal = MyRoles.GetRoles(Request.Headers["ceid"]); 
    } 

请注意,我的示例代码不考虑存储的GenericPrincipal实例列表所需的内存占用。我的目标仅仅是让您了解如何在不使用会话对象的情况下坚持(和终止)用户数据。

20分钟到期机制可以很容易地链接到Session_End事件,因此只要会话结束(如果您使用InProc会话),它就会过期数据。

也请注意,就像会话,此解决方案仅适用于单服务器环境。如果您有一个负载平衡的环境(2台或更多台Web服务器),则必须将数据保存到数据库。

我希望这可以帮助你。如果没有,请让我知道为什么,我会尽我所能来帮助你:)

+0

谢谢,@Alex ...我会尽快尝试。对不起,但我的VS2013的试用版刚刚过期,我为一家大公司工作,所以让他们给我一个实际的MSDN许可证需要的时间比预期的要长:( –

+0

没问题,@FrancineDeGroodTaylor。只要记住保持关注那个静态类的内存占用情况(就像你使用Session对象时一样)如果你需要我,你知道在哪里找到我:) –