我有一个多租户网站(例如几个不同的网站,每个网站都有自己的域,都在同一个项目中,使用MVC区域分开),其中认证cookie在用户登录时手动设置域,以便它可用于所有子域(但不是项目中的其他各个站点,这是不 SSO)。
因此,用户登录x.foo.com,为foo.com设置了cookie域,因此它也适用于y.foo.com和z.foo.com。但是,由于其他域是从同一个项目提供的,因此无法以通常的方式在web.config中设置auth cookie域,而是在用户登录时手动设置:
public HttpCookie GetAuthenticationCookie(string username)
{
var cookieDomain = UrlHelper.GetTopAndSecondLevelDomain();
var authenticationCookie = FormsAuthentication.GetAuthCookie(username, false);
authenticationCookie.Domain = cookieDomain;
return authenticationCookie;
}
这样可以正常工作,但当cookie自动刷新以进行滑动过期时,当然会导致问题。所以我们有一个HTTP模块,它连接到我们的MVC应用程序的PostRequestHandlerExecute
事件中,以查找在请求期间设置到响应中的auth cookie,并覆盖域:
public class AuthenticationCookieDomainInterceptorModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostRequestHandlerExecute += UpdateAuthenticationCookieExpiry;
}
private void UpdateAuthenticationCookieExpiry(object sender, EventArgs e)
{
var app = (HttpApplication) sender;
var cookieDomain = UrlHelper.GetTopAndSecondLevelDomain();
var authenticationCookie = GetCookieFromResponse(app.Context.Response, FormsAuthentication.FormsCookieName);
if (authenticationCookie != null)
{
if (authenticationCookie.Domain == null || !string.Equals(authenticationCookie.Domain, cookieDomain, StringComparison.InvariantCultureIgnoreCase))
{
authenticationCookie.Domain = cookieDomain;
}
}
}
private HttpCookie GetCookieFromResponse(HttpResponse response, string cookieName)
{
var cookies = response.Cookies;
for (var i = 0; i < cookies.Count; i++) {
if (cookies[i].Name == cookieName)
{
return cookies[i];
}
}
return null;
}
}
除非请求发送到我们用来处理AJAX请求的ServiceStack前端,否则它也可以正常运行。在这种情况下,模块正常触发,如果已设置cookie,则选择cookie,按原样更改域,但是当响应被发送回客户端时,将忽略对cookie的更改。
在这种情况下,是否有任何理由不将cookie更改保存到响应中?我的猜测与ServiceStack首先使用HttpHandler挂钩请求周期这一事实有关,因此我们不会经历正常的MVC请求生命周期。