ASP.NET的Cookies、身份验证和会话超时

35

我有一个使用表单验证的asp.net网站,一些信息如用户名、用户ID、电子邮件等会被存储在session中。

我允许用户通过设置身份验证cookie的长时间过期日期来保持登录状态。因此,当用户仍然处于认证状态时,session很容易过期。

我遇到的问题是有时用户的session超时了,但他们仍处于认证状态。例如,我的一个需要认证的用户页面会在其会话处于活动状态时显示“欢迎Mike”,但是一旦它过期,它就会显示“欢迎[空白]”,因为信息不再位于session中,但他们仍处于认证状态。

最好的解决方式是什么?当session信息不再存在时,应该重新同步session信息吗?还是应该将用户信息(用户名、用户ID、电子邮件)移入cookie,并不用担心session超时?

我不想将session长度设置为60分钟或更长的时间。我想要的是,我的用户只需登录一次,然后无需担心必须再次登录,直到他们明确退出登录。

5个回答

20

尽可能避免使用会话,如果不使用会话可以使多服务器部署变得更加容易。也许,名称和电子邮件是cookie的容易选择。很容易伪造cookie,根据您的安全性需求,userID可能不是一个好主意。

表单身份验证cookie是加密的,您可以向这些cookie添加额外的数据(详见下文)。它可能是可破解的,但远不像简单cookie那样容易。下面是我过去使用的代码,稍作修改以删除一些项目特定的细节。在登录控件的LoggedIn事件中调用此代码。

void AddUserIDToAuthCookie(string userID)  
{  
  //There is no way to directly set the userdata portion of a FormAuthenticationTicket  
  //without re-writing the login portion of the Login control  
  //  
  //I find it easier to pull the cookie that the Login control inserted out  
  //and create a new cookie with the userdata set  

  HttpCookie authCookie = Response.Cookies[AUTH_COOKIE];
  if(authCookie == null)
  {
    return;
  }

  Response.Cookies.Remove(AUTH_COOKIE);

  FormsAuthenticationTicket oldTicket = FormsAuthentication.Decrypt(authCookie.Value);
  var newTicket =
    new FormsAuthenticationTicket(oldTicket.Version, oldTicket.Name, oldTicket.IssueDate, oldTicket.Expiration,
                                  oldTicket.IsPersistent, userID, oldTicket.CookiePath);

  authCookie.Value = FormsAuthentication.Encrypt(newTicket);

  Response.Cookies.Add(authCookie);
}

顺便说一句,我从一个旧项目中复制了这个代码,并在这里进行了编辑以删除一些特定于该项目的部分,因此它可能无法编译,但非常接近。

要在您的网页中获取ID...

FormsAuthenticationTicket ticket = ((FormsIdentity) Page.User.Identity).Ticket;
string id = ticket.UserData;

我使用这种机制来存储一个不是 aspnetdb 用户数据的 id。如果所有身份数据都由 aspnetdb 处理,您可能只需要访问 Page.User.Identity 对象。


是的,我很想知道如何向身份验证 cookie 添加详细信息。这可能正是我正在寻找的解决方案! - danifo
我认为 HttpCookie authCookie = Response.Cookies[AUTH_COOKIE]; 应该改为 Request.Cookies - Valamas
我使用了这个答案来帮助我的情况,同时也回答了我在研究过程中发现的另一个人的问题 - https://dev59.com/t2ox5IYBdhLWcg3ww28D#17961503 - Valamas
AddUserIDToAuthCookie()会在验证用户凭据后被调用吗?为什么在将cookie传输到客户端之前要将旧cookie数据放入新cookie中? - Mou

4

个人而言,我会保留20分钟的默认设置,并在您的网站上添加“保持连接”功能。制作一个简单的JavaScript,每5分钟轮询heartbeat.aspx,以保持会话活动状态。这将延长会话和身份验证时间,而不需要保留疯狂的身份验证令牌。

有一些示例(我认为很糟糕)可以实现此功能。最终我使用了基于 AjaxLines's session timeout prevention的某些内容。但是,我没有使用Ajax库,而是直接使用xhtml请求。除了定时调用heartbeat页面的GET之外,实际上不需要任何其他东西。


2

从技术上讲,由于asp.net会话超时,您的用户不应该被注销。这应该/应该受到表单身份验证cookie的控制。

与用户身份验证有关的所有基本信息应保存在表单身份验证票证的USERDATA属性中。这个值不应该保存在会话中。

只保留那些可以重新创建的会话值。

因此,当您创建表单身份验证cookie时,可以将所有基本信息作为票证的一部分传递。

--

您可以做的快速方法是将会话和表单身份验证的超时时间保持一致。这将是一个很好的实践。

每次请求站点时,会话超时会自动延长。

而表单身份验证只在50%的时间过去后才会延长。

这里有关于此的详细信息: 表单身份验证常见问题解答

最简单的方法是在自定义的HttpModule或基础页面中延长表单身份验证的时间,无论您的设计如何。

通过这种方式,您的超时时间将始终保持同步,尽管可能会存在一些轻微的差异。


0

我偏爱使用类似缓存的会话方式。也就是说,尝试从会话中读取,如果值存在则返回它,如果不存在,则从持久化存储(数据库等)中读取,将其放入会话并返回。

为了简化这个过程,创建一个类,在会话中为每个变量添加一个属性,并将类的实例存储在会话中。然后创建一个静态方法来获取类的实例。如果可以的话,稍后我会添加一个示例。


0

没有实际尝试过,但有几件事情我会检查一下。

  • 使用FormsAuthentication类的一个方法/重载,允许您设置持久性cookie。虽然,在我看来,让用户选择勾选“记住我”的框是常规礼仪,而不是强制他们保持登录状态。根据您想要的行为,有许多方法可以做到这一点- SetAuthenticationCookie()和RedirectFromLoginPage()是我首先想到的。

  • 查看FormsAuthentication.GetAuthenticationCookie()。这将生成一个带有身份验证令牌的HTTP cookie,但不会实际设置它,这应该允许您更改所需内容-尽管如果FormsAuthentication模块正在寻找特定值,则更改可能会破坏身份验证。然后,您必须手动将cookie添加到响应中的cookies集合中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接