在 ASP.NET MVC 的会话中存储自定义主体的问题
我遇到了 ASP.NET MVC 的问题,它强制用户在大约 20 分钟不活动后重新登录。
我正在使用表单身份验证,并增加了配置文件中的超时:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="9999999" />
</authentication>
我还在配置文件中将会话超时设置为:
<sessionState timeout="120"></sessionState>
我基于 Rockford Lhotka 的 CSLA ASP.NET MVC 示例,并具有在我的 global.asax 中:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Handler is IRequiresSessionState)
{
if (Csla.ApplicationContext.AuthenticationType == "Windows")
return;
System.Security.Principal.IPrincipal principal;
try
{
principal = (System.Security.Principal.IPrincipal)
HttpContext.Current.Session[MyMembershipProvider.SESSION_KEY];
}
catch
{
principal = null;
}
if (principal == null)
{
if (this.User.Identity.IsAuthenticated && this.User.Identity is FormsIdentity)
{
// no principal in session, but ASP.NET token
// still valid - so sign out ASP.NET
FormsAuthentication.SignOut();
this.Response.Redirect(this.Request.Url.PathAndQuery);
}
// didn't get a principal from Session, so
// set it to an unauthenticted PTPrincipal
BusinessPrincipal.Logout();
}
else
{
// use the principal from Session
Csla.ApplicationContext.User = principal;
}
}
}
据我所知,它应该仅在 120 分钟不活动后超时……但由于某种原因,它似乎总是在 20 分钟不活动后超时。我知道为什么会发生这种情况,有什么想法吗?
我正在考虑仅转储表单身份验证并通过会话自己处理它,但我担心我会失去 [Authorize] 属性等功能。尽量不要走这条路。
是否可以将我的自定义主体对象存储为 cookie?我只是不想为每个页面或操作验证/授权用户。
我正在快速脱发! =)
I am running into an issue with ASP.NET MVC where it is forcing the user to log back in after about 20 mins of inactivity.
I am using Forms Authentication and have increased the time-out in the config file as:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="9999999" />
</authentication>
I am also setting the session time-out in the config file as:
<sessionState timeout="120"></sessionState>
I am basing this off of Rockford Lhotka's CSLA ASP.NET MVC example and have the following in my global.asax:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Handler is IRequiresSessionState)
{
if (Csla.ApplicationContext.AuthenticationType == "Windows")
return;
System.Security.Principal.IPrincipal principal;
try
{
principal = (System.Security.Principal.IPrincipal)
HttpContext.Current.Session[MyMembershipProvider.SESSION_KEY];
}
catch
{
principal = null;
}
if (principal == null)
{
if (this.User.Identity.IsAuthenticated && this.User.Identity is FormsIdentity)
{
// no principal in session, but ASP.NET token
// still valid - so sign out ASP.NET
FormsAuthentication.SignOut();
this.Response.Redirect(this.Request.Url.PathAndQuery);
}
// didn't get a principal from Session, so
// set it to an unauthenticted PTPrincipal
BusinessPrincipal.Logout();
}
else
{
// use the principal from Session
Csla.ApplicationContext.User = principal;
}
}
}
From what I can tell it should ONLY time-out after 120 minutes of inactivity ... but for some reason it always seems to time-out after 20 minutes of inactivity. I have know idea why this is happening, any ideas?
I am toying with the idea of just dumping Forms Authentication and handling it myself via Session, but I'm afraid I would lose functionality like [Authorize] attributes and so on. Trying not to go down this path.
Is it possible to store my custom principal object as a cookie? I just don't want to have to authenticate/authorize a user for every single page or action.
I'm losing hair ... rapidly! =)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
正如您从得到的答案中注意到的那样,将 FormsAuthentication 与 SessionState 混合在一起在很多层面上都是一个坏主意。
如果描述您的自定义主体的信息很小,我建议将其存储在表单票证的 UserData 成员中。这就是它的用途。
然后,您的自定义数据(仅对有效票证有效)将与票证一起存储。
许多问题得到解决,并且避免了很多代码。
这里是可以帮助您处理票证的助手类。
注意:实际上,最大 http cookie 大小略低于官方的 4k 限制,加密将其大约减少一半。
如果您可以确保您的票据(包括主要数据)小于 2k,那么您就可以开始了。为您的主体创建自定义序列化会有所帮助,例如,如果您的数据能够配合,名称=值对会非常有效。
祝你好运。
Mixing concerns of FormsAuthentication with SessionState is just a bad idea on many levels, as you are noticing from the answers you are getting.
If the information describing your custom principal is small, I would suggest storing it in the UserData member of the forms ticket. That is what it is there for.
Then your custom data, which is only valid with a valid ticket, is stored with the ticket.
Many problems solved and mucho code obviated.
Here is a helper class that can help you with your ticket.
CAVEAT: In practice the max http cookie size is just shy of the official 4k limit and Encryption cuts that in half approximately.
If you can ensure that your ticket, including principal data will fit into <2k you should be good to go. Creating a custom serialization for your principal can help, e.g. name=value pairs works great if your data will cooperate.
Good luck.
通过会话处理它可能还不够。因为它可能是 IIS 回收您的应用程序,从而导致所有会话被放弃。
请参阅
Handling it via Session may not be enough. Because it could be IIS recycling your application, therefor causing all the sessions to be abandoned.
See
希望你现在已经解决了这个问题,但如果其他人遇到同样的问题,我一直负责调试使用相同模板编写的一些代码,这里有一些想法:
1)表单票证有超时编码成它的值。大多数示例代码都会对此超时进行硬编码,而不是从表单身份验证配置中提取,因此,如果您只是查看 web.config,一切看起来都很好,但您的自定义安全代码会忽略 web.config 值。查看“new FormsAuthenticationTicket”的代码,看看您在过期时间内做了什么。
2) 表单 cookie 在其 cookie 值中设置了超时。一些示例代码对此超时进行了硬编码。查看您是否在安全 cookie 上设置了 cookie.Expires。 (自定义身份验证往往会在这里手动构建比您预期更多的代码,因为 FormsAuthentication 方法不会公开 make-a-cookie-with-userdata 方法,并且您通常希望使用 userdata 来存储一些信息,例如角色in)
3) 有些客户端不会在响应重定向上设置 cookie。有时即使他们这样做了,你也会得到一个与你设置的不同的cookie。例如,如果您在任何时候更改了应用程序路径或域,则用户可能拥有两个有效的 cookie,而当您尝试将它们重新登录到此处时,您只会清除一个。现在,这段代码基本上是“用户有一些会话信息,并且已登录,但他们的会话不包含我期望的主体,所以我将他们重定向到再次登录。”好吧,如果他们不听你的身份验证 cookie,或者有一个你不期望的身份验证 cookie(也许你在某个时刻更改了你的域或路径值,并且他们仍然设置了 /oldpath cookie),这可能会无限循环。我建议您一旦发现会话服务器端没有您想要的数据,就立即删除会话服务器端:Session.Clear() - 这使您在重定向后不太可能陷入这种情况。 (从恢复服务器端而不信任客户端行为的角度来看,继续重建主体对象并将其放入会话中实际上稍微安全一些,但我可以看到这会如何减少安全。)
仅执行 Server.Transfer 到登录页面比依赖 cookie 更改重定向来正常工作也更安全。如果您确实陷入了重定向循环,server.transfer 一定会结束它。
Hopefully you got this solved by now, but in case somebody else comes along with the same issues, I've been responsible for debugging some code written using the same template, and here are a few thoughts:
1) The forms ticket has a timeout encoded into its value. Most of the example code out there hard-codes this timeout instead of pulling from the forms auth configuration, so if you're just looking at your web.config everything can look fine but your custom security code is ignoring the web.config value. Look through your code for "new FormsAuthenticationTicket" and see what you are doing for the expiration time.
2) The forms cookie has a timeout set in its cookie value. Some of the example code out there hard-codes this timeout. Look and see if you are setting cookie.Expires on your security cookie. (Custom auth tends to hand-build more code here than you would expect because the FormsAuthentication methods don't expose the make-a-cookie-with-userdata method, and you generally want to use userdata to store a bit of info like roles in)
3) Some clients will not set a cookie on response redirect. And sometimes even if they do, you'll get back a cookie other than the one you set. For example, if you have changed the app path or domain at any point, it's possible for the user to have two valid cookies, and you're only clearing one when you try to log them back in here. Now, this code basically reads "The user has some session info, and was logged in, but their session didn't contain the principal I expected it to, so I redirect them to login again." Well, if they don't listen to your auth cookie, or have an auth cookie you don't expect (maybe you changed your domain or path values at some point and they have a /oldpath cookie still set), this can infinite loop. I recommend nuking the session server-side as soon as you find out that it doesn't have the data you want: Session.Clear() - this leaves you less likely to end up in this situation after a redirect. (From a recover-server-side-without-trusting-the-client-to-behave perspective, it's actually slightly safer to go ahead and reconstruct the principal object and put it into the session, but I can see how this would be less secure.)
It's also safer to just do a Server.Transfer to the login page rather than relying on a cookie-changing redirect to work right. If you do end up in a redirect loop, server.transfer is guaranteed to end it.
您是否也在使用会员提供商进行授权?如果是这样,您可能需要查看 userIsOnlineTimeWindow 属性。默认也是 20 分钟。
Are you using the membership provider for authorization also? If so you may want to look at the userIsOnlineTimeWindow attribute. The default for this is also 20 minutes.