ASP.NET MVC3 Forms身份验证用户登录会话续订

时间:2012-02-05 17:43:04

标签: ajax asp.net-mvc-3 authentication

我有一个AJAX方法来调用服务器返回“.ASPXAUTH”cookie到期时间。 当auth cookie出现时,它可以正常工作。

此外,我想用另一个AJAX调用续订用户登录会话。我有一个空白的方法“RenewSession”,它只是用于调用服务器。有没有办法使用表单身份验证? 问题是,当我向服务器发出请求以“RenewSession”方法更新会话时,Response.Cookies数组总是包含0个项目。但实际上当“.ASPXAUTH”cookie到期时间达到0时,它会更新。

所以任何人都可以解释它是浏览器还是ASP.NET / MVC的行为? 也许我需要将滑动过期设置为“true”? 或者也许在我的续订方法中,我应该重新登录用户并在响应中添加一个新的cookie?

谢谢!

1 个答案:

答案 0 :(得分:5)

FormsAuthentication到期实际上只有两个部分:

  • 认证凭证到期
  • 包含故障单的Cookie过期

如果要关闭滑动过期,并手动续订故障单,则需要续订故障单并将新的身份验证cookie返回给浏览器。

Response.Cookies数组为空,除非您(或其他代码)向其添加内容。它仅用于添加 new 或其内容/过期/其他已更改的Cookie。空Response.Cookies仅表示没有任何更改 - 浏览器将保留已有的Cookie(直到它们过期)并仍然在下一个请求时发送它们。

修改Cookie内容或过期的标准方法是获取浏览器发送的cookie(来自Request.Cookies),修改它,然后将其添加到Response.Cookies

以下是一些手动更新身份验证cookie的示例代码(disclamer:彻底测试并思考):

// You could also get the ticket from
// Request.Cookies using FormsAuthentication.Decode
FormsIdentity identity = HttpContext.Current.User.Identity as FormsIdentity;
if (identity == null) return; // User isn't authenticated

// Renew the ticket - you could also create a new ticket manually 
// (see * below for an example), if you want to get rid of ASP.NET's 
// rather confusing renew-if-old policy:
FormsAuthenticationTicket ticket = 
   FormsAuthentication.RenewTicketIfOld(identity.Ticket);

string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
   FormsAuthentication.FormsCookieName,
   encryptedTicket
);

// Better keep this (see * below):
cookie.Secure = FormsAuthentication.RequireSSL;
cookie.HttpOnly = true;

// Isn't a security issue if this is set too long - the ticket contained
// within will still expire after the set time, and the server will timeout
// the auth session on the next request.
// But let's just keep cookie and ticket in sync:
cookie.Expire = ticket.Expiration;

// Add cookie to response to send the changes to the browser:
HttpContext.Current.Response.Cookies.Add(cookie);

请注意,FormsAuthentication.RenewTicketIfOld()并不总是续订故障单。只有在剩余的到期时间不到一半时才会续订。即,如果web.config中的超时设置为20分钟并且在创建故障单后7分钟调用RenewTicketIfOld,则不会续订故障单,并且还剩下13分钟。如果在例如之后调用它12分钟,它将更新为20分钟。

这是因为每次请求都会由slidingExpiration使用RenewTicketIfOld,因此会在每个请求上发回一个新的cookie(将到期时间重置为[timeout]分钟)。只有在至少一半的时间过去后才发送新的票证cookie才能消除大量的cookie开销 - 这会让开发人员和最终用户感到困惑。

*)在cookie.Secure上,请参阅Hanselman:Weird Timeouts - 这只是确保如果在web.config中设置了RequireSSL,那么cookie将尊重它,这可以避免许多调试噩梦,如果你曾经将网站移至SSL。