Повторная инициализация context.User после тайм-аута FormsAuthenticationTicket - PullRequest
1 голос
/ 09 февраля 2012

В нашем приложении мы реализовали проверку подлинности на основе ролевых форм. Это было обработано с помощью RoleModule, где мы сохраняем данные роли в cookie, и каждый раз, когда мы читаем данные из файла cookie и создаем экземпляр объекта IPrincipal. Этот код выполняется методом Application_OnPostAcquireRequestState:

 HttpApplication application = source as HttpApplication;
 HttpContext context = application.Context;

if (context.User.Identity.IsAuthenticated &&
      (!Roles.CookieRequireSSL || context.Request.IsSecureConnection))
{
//Read the roles data from the Roles cookie..

context.User = new CustomPrincipal(context.User.Identity, cookieValue);
Thread.CurrentPrincipal = context.User;
}

Это инициализирует объект context.User. Каждый раз, когда к серверу делается запрос, пользователь аутентифицируется с использованием вышеуказанного потока. В Application_EndRequest мы обновляем cookie-файл ролей текущими данными основного объекта.

На нашей странице Global.asax есть метод FormsAuthentication_OnAuthenticate, на котором мы читаем куки, обновляем куки и обновляем билет, если он истек. Также в этом методе мы пытаемся установить значение имени пользователя в объекте сеанса, если срок действия билета истек.

FormsAuthentication oldTicket = FormsAuthentication.Decrypt(context.Request.Cookies[FormsAuthentication.FormsCookieName].Value);
if(oldTicket != null)
{
    if(oldTicket.Expired)
    {
        try
        {
            HttpContext.Current.Session["UserName"] = userName;
        }
        catch
        {
            //Log error.
        }

    FormsAuthentication newTicket =  new FormsAuthenticationTicket(oldTicket.Version, oldTicket.Name, DateTime.Now,
            DateTime.Now.AddMinutes(30), oldTicket.IsPersistent, oldTicket.UserData);

    string encryptedTicket = FormsAuthentication.Encrypt(newTicket);
    HttpCookie httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    if (isPersistent)
    {
        httpCookie.Expires = DateTime.Now.AddMinutes(300);
    }
}

Вот наша настройка форм в web.config:

   <forms defaultUrl="Default.aspx" domain="" loginUrl="Login.aspx" name=".ASPXFORMSAUTH" timeout="20" slidingExpiration="true" />

Время ожидания сеанса составляет 20 минут.

Проблема : если пользователь простаивает более 30 минут (что является продолжительностью времени обновления билета FormsAuth), значение context.User.Identity.IsAuthenticated в ролевым модулем является false, а context.User устанавливается как NULL. Теперь, когда пользователь запрашивает страницу, он перенаправляется на страницу входа. Тем не менее печенье все еще там. Если снова пользователь пытается запросить страницу, свойство context.User.IsAuthenticated устанавливается на true, и пользователь перенаправляется на соответствующая страница. Кроме того, в методе FormsAuthentication_OnAuthenticate, когда я пытаюсь установить значение сеанса, он выдает ошибку, поскольку объект сеанса равен NULL.

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

Как мне этого добиться? Если я не ошибаюсь, настройка context.User должна решить цель, но как мне это сделать?

Дополнительная информация:

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

Event code: 4005 
Event message: Forms authentication failed for the request. Reason: The ticket supplied has expired. 
Event time: 08-02-2012 20:02:05 
Event time (UTC): 08-02-2012 14:32:05 
Event ID: 048e3238ade94fd6a7289bac36d130ef 
Event sequence: 76 
Event occurrence: 2 
Event detail code: 50202 

Process information: 
Process ID: 21692 
Process name: w3wp.exe 
Account name: IIS APPPOOL\ASP.NET v4.0 Classic 

Я использую стандартные настройки машинных ключей, хранящиеся в web.config, а не автоматически сгенерированные. Кроме того, я проверил идентификатор процесса и тот же для всех ошибок.

1 Ответ

1 голос
/ 11 февраля 2012

Я наконец решил проблему.Происходило следующее: по истечении времени ожидания билета FormsAuthentication FormsAuthentication_OnAuthenticate не удалось установить объект context.User, как указано в документации MSDN для события Authenticate:

Если вы не укажете значение для свойства User во время события FormsAuthentication_OnAuthenticate, будет использоваться идентификатор, указанный в билете проверки подлинности форм в файле cookie или в URL-адресе.не устанавливается ticket.Name с именем пользователя пользователя.Это пустая строка.Следовательно, это может быть случай, когда событие Authenticate не смогло идентифицировать пользователя и создать экземпляр FormsIdentity.В качестве решения, когда я обновляю просроченный билет, я также создаю объект GenericIdentity и затем использую его для установки context.User.

IIdentity identity = new GenericIdentity(username, "Forms");
context.User = new CustomPrincipal(identity);
...