Owin 如何在 Application_EndRequest 阶段之后设置 Asp.Net 身份验证 cookie?
How is Owin able to set the Asp.Net Identity authentication cookies after the Application_EndRequest stage?
作为测试,我使用 Visual Studio 2013 年的最新模板创建了一个新的 Asp.Net MVC5 应用程序。我将以下方法添加到 Global.asax.cs:
protected void Application_PreSendRequestHeaders()
{
Response.AppendCookie(new HttpCookie("TotalNumberOfCookiesInApplication_EndRequestIs", Response.Cookies.Count + string.Empty));
}
当我启动应用程序并使用注册用户的凭据执行 POST 到 /Account/Login 时,返回给客户端的 cookie 是:
请注意,我添加的自定义 cookie 显示在调用 Application_PreSendRequestHeaders() 时响应中没有设置任何 cookie。尽管如此,所有 Auth cookie 都会到达客户端。我的理解是 Application_PreSendRequestHeaders() 是我们可以 "hook" 修改 cookie 的最后阶段。 Owin 中间件之后是否能够以某种方式添加 cookie,还是我遗漏了什么?
(如果您有兴趣,我做这一切的动机是:我正在尝试将身份验证 cookie 的域修改为“.abc.com”,其中 "abc.com" 是请求 URI 中主机的最后两部分。我想这样做以支持跨多个子域的身份验证。在全局 Owin 配置的上下文中设置 CookieDomain (IAppBuilder
) 是不够的,因为请求主机在我们的 debug/staging/production 环境之间变化,而且我们通常先将生产代码部署到 Azure 暂存中进行测试,然后再进行 VIP 交换)。
(另请注意,我知道像 this one 这样的帖子,但它没有解释 cookie 的实际设置位置)
编辑:
根据更多的搜索,我似乎查错了管道。 Owin 有自己的管道,所以我找到了 this post,它描述了我们如何连接到它。维奥拉……有饼干。如果有人能确认这确实是最明智的做法,那就太好了。
编辑 2:
最终决定查看 Katana 源代码,发现我需要做的就是在我的 CookieAuthenticationProvider 中添加以下代码来设置我的 cookie 域
OnResponseSignIn = context =>
{
// Example only!
context.CookieOptions.Domain = context.Request.Uri.Host;
},
OnResponseSignOut = context =>
{
// Example only!
context.CookieOptions.Domain = context.Request.Uri.Host;
}
编辑 3:
对于我的案例来说,一个更简洁的解决方案是使用自定义 cookie 管理器,它根据当前请求 URI 设置 cookie 域:
/// <summary>
/// This class simply appends the cookie domain to the usual auth cookies
/// </summary>
public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
private readonly ChunkingCookieManager _chunkingCookieManager;
public ChunkingCookieManagerWithSubdomains()
{
_chunkingCookieManager = new ChunkingCookieManager();
}
public string GetRequestCookie(IOwinContext context, string key)
{
return _chunkingCookieManager.GetRequestCookie(context, key);
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.AppendResponseCookie(context, key, value, options);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.DeleteCookie(context, key, options);
}
}
...然后在 Owin 设置的 Cookie Auth 选项中设置:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
CookieManager = new ChunkingCookieManagerWithSubdomains(),
...
}
});
希望对遇到同样问题的人有所帮助。
应 Tieson 的要求,这里是我在上面的原始 post 中编辑的摘要,作为答复。
建议的解决方案:使用自定义 cookie 管理器。
/// <summary>
/// This class simply appends the cookie domain to the usual auth cookies
/// </summary>
public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
private readonly ChunkingCookieManager _chunkingCookieManager;
public ChunkingCookieManagerWithSubdomains()
{
_chunkingCookieManager = new ChunkingCookieManager();
}
public string GetRequestCookie(IOwinContext context, string key)
{
return _chunkingCookieManager.GetRequestCookie(context, key);
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.AppendResponseCookie(context, key, value, options);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.DeleteCookie(context, key, options);
}
}
...然后可以在 Owin 设置中的 Cookie 身份验证选项中进行设置:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
CookieManager = new ChunkingCookieManagerWithSubdomains(),
...
}
});
作为测试,我使用 Visual Studio 2013 年的最新模板创建了一个新的 Asp.Net MVC5 应用程序。我将以下方法添加到 Global.asax.cs:
protected void Application_PreSendRequestHeaders()
{
Response.AppendCookie(new HttpCookie("TotalNumberOfCookiesInApplication_EndRequestIs", Response.Cookies.Count + string.Empty));
}
当我启动应用程序并使用注册用户的凭据执行 POST 到 /Account/Login 时,返回给客户端的 cookie 是:
请注意,我添加的自定义 cookie 显示在调用 Application_PreSendRequestHeaders() 时响应中没有设置任何 cookie。尽管如此,所有 Auth cookie 都会到达客户端。我的理解是 Application_PreSendRequestHeaders() 是我们可以 "hook" 修改 cookie 的最后阶段。 Owin 中间件之后是否能够以某种方式添加 cookie,还是我遗漏了什么?
(如果您有兴趣,我做这一切的动机是:我正在尝试将身份验证 cookie 的域修改为“.abc.com”,其中 "abc.com" 是请求 URI 中主机的最后两部分。我想这样做以支持跨多个子域的身份验证。在全局 Owin 配置的上下文中设置 CookieDomain (IAppBuilder
) 是不够的,因为请求主机在我们的 debug/staging/production 环境之间变化,而且我们通常先将生产代码部署到 Azure 暂存中进行测试,然后再进行 VIP 交换)。
(另请注意,我知道像 this one 这样的帖子,但它没有解释 cookie 的实际设置位置)
编辑:
根据更多的搜索,我似乎查错了管道。 Owin 有自己的管道,所以我找到了 this post,它描述了我们如何连接到它。维奥拉……有饼干。如果有人能确认这确实是最明智的做法,那就太好了。
编辑 2:
最终决定查看 Katana 源代码,发现我需要做的就是在我的 CookieAuthenticationProvider 中添加以下代码来设置我的 cookie 域
OnResponseSignIn = context =>
{
// Example only!
context.CookieOptions.Domain = context.Request.Uri.Host;
},
OnResponseSignOut = context =>
{
// Example only!
context.CookieOptions.Domain = context.Request.Uri.Host;
}
编辑 3:
对于我的案例来说,一个更简洁的解决方案是使用自定义 cookie 管理器,它根据当前请求 URI 设置 cookie 域:
/// <summary>
/// This class simply appends the cookie domain to the usual auth cookies
/// </summary>
public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
private readonly ChunkingCookieManager _chunkingCookieManager;
public ChunkingCookieManagerWithSubdomains()
{
_chunkingCookieManager = new ChunkingCookieManager();
}
public string GetRequestCookie(IOwinContext context, string key)
{
return _chunkingCookieManager.GetRequestCookie(context, key);
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.AppendResponseCookie(context, key, value, options);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.DeleteCookie(context, key, options);
}
}
...然后在 Owin 设置的 Cookie Auth 选项中设置:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
CookieManager = new ChunkingCookieManagerWithSubdomains(),
...
}
});
希望对遇到同样问题的人有所帮助。
应 Tieson 的要求,这里是我在上面的原始 post 中编辑的摘要,作为答复。
建议的解决方案:使用自定义 cookie 管理器。
/// <summary>
/// This class simply appends the cookie domain to the usual auth cookies
/// </summary>
public class ChunkingCookieManagerWithSubdomains : ICookieManager
{
private readonly ChunkingCookieManager _chunkingCookieManager;
public ChunkingCookieManagerWithSubdomains()
{
_chunkingCookieManager = new ChunkingCookieManager();
}
public string GetRequestCookie(IOwinContext context, string key)
{
return _chunkingCookieManager.GetRequestCookie(context, key);
}
public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.AppendResponseCookie(context, key, value, options);
}
public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
{
// Simplification (use the context parameter to get the required request info)
options.Domain = ".domainBasedOnRequestInContext.com";
_chunkingCookieManager.DeleteCookie(context, key, options);
}
}
...然后可以在 Owin 设置中的 Cookie 身份验证选项中进行设置:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
CookieManager = new ChunkingCookieManagerWithSubdomains(),
...
}
});