在 HttpAuthenticationContext 中为 IAuthenticationFilter 设置 Cookie 值
Setting Cookie values in HttpAuthenticationContext for IAuthenticationFilter
我需要在 WebAPI 管道的身份验证步骤中 read/write cookie。我为此创建了一个自定义过滤器。
为了遵守自托管概念,访问 cookie 并将其写入客户端的安全方式是什么? Rick Strahl 评论说,如果我们使用 HttpContext.Current.Response.Cookies.Add()
,并且我的应用程序是自托管的,则上下文 may/will 不存在。
那么我如何使用 HttpAuthenticationContext
将 cookie 写到客户端并且仍然是自托管安全的?
HttpAuthenticationContext authContext;
authContext.ActionContext.Response.Headers.AddCookies(/*cookies */);
edit2
HttpAuthenticationContext authContext;
var myCookie = new CookieHeaderValue("key", "value")
authContext.ActionContext.Response.Headers.Add("Set-Cookie", myCookie.ToString());
编辑
AddCookie是位于System.Net.Http.Formatting.dll的扩展方法(自v5.2.2.0版本起),扩展方法由static class HttpResponseHeadersExtensions声明,位于namespace System.Net.Http.
如果找不到扩展方法,请尝试定位 HttpResponseHeadersExtensions class.
如果找不到 HttpResponseHeadersExtensions class,请尝试升级 Web Api 2 库。升级每个项目的 WebApi2 的所有 nuget 包的最有效方法(对于像我这样讨厌升级 nuget 包的人),是对术语 [=] 的 .config 文件执行全局 search/replace 45=](其中 x.x.x 是被 'version="5.2.2" targetFramework="net45"'
替换的旧版本
在最坏的情况下,如果你的老板或你妈妈不让你升级nuget包,你总是可以采取叛逆的态度反编译包含AddCookie的代码,看起来像这样:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Http.Headers;
using System.Net.Http.Properties;
using System.Web.Http;
namespace System.Net.Http
{
/// <summary> Provides extension methods for the <see cref="T:System.Net.Http.Headers.HttpResponseHeaders" /> class. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class HttpResponseHeadersExtensions
{
private const string SetCookie = "Set-Cookie";
/// <summary> Adds cookies to a response. Each Set-Cookie header is represented as one <see cref="T:System.Net.Http.Headers.CookieHeaderValue" /> instance. A <see cref="T:System.Net.Http.Headers.CookieHeaderValue" /> contains information about the domain, path, and other cookie information as well as one or more <see cref="T:System.Net.Http.Headers.CookieState" /> instances. Each <see cref="T:System.Net.Http.Headers.CookieState" /> instance contains a cookie name and whatever cookie state is associate with that name. The state is in the form of a <see cref="T:System.Collections.Specialized.NameValueCollection" /> which on the wire is encoded as HTML Form URL-encoded data. This representation allows for multiple related "cookies" to be carried within the same Cookie header while still providing separation between each cookie state. A sample Cookie header is shown below. In this example, there are two <see cref="T:System.Net.Http.Headers.CookieState" /> with names state1 and state2 respectively. Further, each cookie state contains two name/value pairs (name1/value1 and name2/value2) and (name3/value3 and name4/value4). <code> Set-Cookie: state1:name1=value1&amp;name2=value2; state2:name3=value3&amp;name4=value4; domain=domain1; path=path1; </code></summary>
/// <param name="headers">The response headers</param>
/// <param name="cookies">The cookie values to add to the response.</param>
public static void AddCookies(this HttpResponseHeaders headers, IEnumerable<CookieHeaderValue> cookies)
{
if (headers == null)
{
throw Error.ArgumentNull("headers");
}
if (cookies == null)
{
throw Error.ArgumentNull("cookies");
}
foreach (CookieHeaderValue current in cookies)
{
if (current == null)
{
throw Error.Argument("cookies", Resources.CookieNull, new object[0]);
}
headers.TryAddWithoutValidation("Set-Cookie", current.ToString());
}
}
}
}
- 当你意识到在 webapi2 中添加 cookie 只需一行代码即可完成时,你会觉得花这么多时间寻找扩展方法有点愚蠢:
headers.TryAddWithoutValidation("Set-Cookie", new CookieHeaderValue("key", "value")); //where headers is a HttpResponseHeaders
您无法从 IAuthenticationFilter.AuthenticateAsync()
中访问 authContext.ActionContext.Response
。好吧,实际上你可以,但只能设置一个新的响应并缩短管道的其余部分。
我遇到了同样的问题(需要在成功验证后设置 cookie),除了 IAuthenticationFilter
:
之外,还通过实施 IActionFilter
解决了这个问题
async Task<HttpResponseMessage> IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
// Process the request pipeline and get the response (this causes the action to be executed)
HttpResponseMessage response = await continuation();
// Here you get access to:
// - The request (actionContext.Request)
// - The response (response) and its cookies (response.Headers.AddCookies())
// - The principal (actionContext.ControllerContext.RequestContext.Principal)
return response;
}
参见:
我需要在 WebAPI 管道的身份验证步骤中 read/write cookie。我为此创建了一个自定义过滤器。
为了遵守自托管概念,访问 cookie 并将其写入客户端的安全方式是什么? Rick Strahl 评论说,如果我们使用 HttpContext.Current.Response.Cookies.Add()
,并且我的应用程序是自托管的,则上下文 may/will 不存在。
那么我如何使用 HttpAuthenticationContext
将 cookie 写到客户端并且仍然是自托管安全的?
HttpAuthenticationContext authContext;
authContext.ActionContext.Response.Headers.AddCookies(/*cookies */);
edit2
HttpAuthenticationContext authContext;
var myCookie = new CookieHeaderValue("key", "value")
authContext.ActionContext.Response.Headers.Add("Set-Cookie", myCookie.ToString());
编辑
AddCookie是位于System.Net.Http.Formatting.dll的扩展方法(自v5.2.2.0版本起),扩展方法由static class HttpResponseHeadersExtensions声明,位于namespace System.Net.Http.
如果找不到扩展方法,请尝试定位 HttpResponseHeadersExtensions class.
如果找不到 HttpResponseHeadersExtensions class,请尝试升级 Web Api 2 库。升级每个项目的 WebApi2 的所有 nuget 包的最有效方法(对于像我这样讨厌升级 nuget 包的人),是对术语 [=] 的 .config 文件执行全局 search/replace 45=](其中 x.x.x 是被 'version="5.2.2" targetFramework="net45"'
替换的旧版本
在最坏的情况下,如果你的老板或你妈妈不让你升级nuget包,你总是可以采取叛逆的态度反编译包含AddCookie的代码,看起来像这样:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Net.Http.Headers; using System.Net.Http.Properties; using System.Web.Http; namespace System.Net.Http { /// <summary> Provides extension methods for the <see cref="T:System.Net.Http.Headers.HttpResponseHeaders" /> class. </summary> [EditorBrowsable(EditorBrowsableState.Never)] public static class HttpResponseHeadersExtensions { private const string SetCookie = "Set-Cookie"; /// <summary> Adds cookies to a response. Each Set-Cookie header is represented as one <see cref="T:System.Net.Http.Headers.CookieHeaderValue" /> instance. A <see cref="T:System.Net.Http.Headers.CookieHeaderValue" /> contains information about the domain, path, and other cookie information as well as one or more <see cref="T:System.Net.Http.Headers.CookieState" /> instances. Each <see cref="T:System.Net.Http.Headers.CookieState" /> instance contains a cookie name and whatever cookie state is associate with that name. The state is in the form of a <see cref="T:System.Collections.Specialized.NameValueCollection" /> which on the wire is encoded as HTML Form URL-encoded data. This representation allows for multiple related "cookies" to be carried within the same Cookie header while still providing separation between each cookie state. A sample Cookie header is shown below. In this example, there are two <see cref="T:System.Net.Http.Headers.CookieState" /> with names state1 and state2 respectively. Further, each cookie state contains two name/value pairs (name1/value1 and name2/value2) and (name3/value3 and name4/value4). <code> Set-Cookie: state1:name1=value1&amp;name2=value2; state2:name3=value3&amp;name4=value4; domain=domain1; path=path1; </code></summary> /// <param name="headers">The response headers</param> /// <param name="cookies">The cookie values to add to the response.</param> public static void AddCookies(this HttpResponseHeaders headers, IEnumerable<CookieHeaderValue> cookies) { if (headers == null) { throw Error.ArgumentNull("headers"); } if (cookies == null) { throw Error.ArgumentNull("cookies"); } foreach (CookieHeaderValue current in cookies) { if (current == null) { throw Error.Argument("cookies", Resources.CookieNull, new object[0]); } headers.TryAddWithoutValidation("Set-Cookie", current.ToString()); } } } }
- 当你意识到在 webapi2 中添加 cookie 只需一行代码即可完成时,你会觉得花这么多时间寻找扩展方法有点愚蠢:
headers.TryAddWithoutValidation("Set-Cookie", new CookieHeaderValue("key", "value")); //where headers is a HttpResponseHeaders
您无法从 IAuthenticationFilter.AuthenticateAsync()
中访问 authContext.ActionContext.Response
。好吧,实际上你可以,但只能设置一个新的响应并缩短管道的其余部分。
我遇到了同样的问题(需要在成功验证后设置 cookie),除了 IAuthenticationFilter
:
IActionFilter
解决了这个问题
async Task<HttpResponseMessage> IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
// Process the request pipeline and get the response (this causes the action to be executed)
HttpResponseMessage response = await continuation();
// Here you get access to:
// - The request (actionContext.Request)
// - The response (response) and its cookies (response.Headers.AddCookies())
// - The principal (actionContext.ControllerContext.RequestContext.Principal)
return response;
}
参见: