2015-05-29 2 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; 

Проблема заключается в том, что мы должны использовать веб-службу, чтобы получить роль, и потому, что вызов делается каждый раз, когда каждый пользователь посещает страницу, веб служба попадает слишком много раз.

Идеальное решение было бы, если бы мы могли хранить роли в переменной сеанса, однако сеанс недоступен в 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; многие люди играют свою роль, поэтому хранение в файле cookie, который имеет HttpOnly (доступно только на сервере), установленном в true, является хорошим решением. –

+0

Если вам не нравится использовать файл cookie, возможно, [MemoryCache] (https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache%28v=vs.110%29.aspx) является возможным решением? –

ответ

1

Я бы создал статический класс для хранения списка ролей для всех текущих пользователей (в основном, на основе идеи словаря): если роли для данного идентификатора отсутствуют в списке, мы извлекаем их из веб-службы , В противном случае мы возвращаем сохраненные роли.

Нам нужны средства для истечения срока действия данных после определенного количества неактивности пользователя (мы не хотим постоянно сохранять все роли для всех пользователей в памяти), поэтому мы реализуем наш собственный механизм истечения срока действия (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. Моя цель состоит исключительно в том, чтобы дать вам представление о том, как переносить (и истекать) данные пользователя без использования объекта Session.

Механизм истечения 20 минут может быть легко связан с событием Session_End, так что он истечет как только закончится сеанс (если вы используете сеансы InProc).

Также обратите внимание, что, как и сеансы, это решение работает только в средах с одним сервером. Если у вас есть сбалансированная по нагрузке среда (2 или более веб-серверов), вам придется сохранять данные в БД.

Я надеюсь, что это поможет вам. Если это не так, пожалуйста, дайте мне знать, почему, и я постараюсь изо всех сил помочь вам :)

+0

Спасибо, @Alex ... Я попробую это, как только смогу. Извините за задержку, но моя пробная версия VS2013 просто истек, и я работаю в крупной компании, поэтому получить их, чтобы дать мне реальную лицензию MSDN, занимает больше времени, чем можно было бы надеяться :( –

+0

Нет проблем, @FrancineDeGroodTaylor. взгляд на область памяти этого статического класса (как и при использовании объекта Session). Если вам нужно, вы знаете, где меня найти :) –

Смежные вопросы