【问题标题】:Setting Cookie values in HttpAuthenticationContext for IAuthenticationFilter在 HttpAuthenticationContext 中为 IAuthenticationFilter 设置 Cookie 值
【发布时间】:2015-06-05 09:26:40
【问题描述】:

我需要在 WebAPI 管道的身份验证步骤中读取/写入 cookie。我为此创建了一个自定义过滤器。

为了遵守自托管概念,什么是访问 cookie 并将其写入客户端的安全方法? Rick Strahl 评论说,如果我们使用 HttpContext.Current.Response.Cookies.Add(),并且我的应用程序是自托管的,那么上下文可能/不会存在。

那么我如何使用 HttpAuthenticationContext 将 cookie 写入客户端并且仍然是自托管安全的?

【问题讨论】:

    标签: c# cookies asp.net-web-api


    【解决方案1】:

    您无法从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;
    }
    

    见:Set cookie from Web Api 2 IAuthenticationFilter AuthenticateAsync method

    【讨论】:

      【解决方案2】:
      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 版本开始),扩展方法由位于命名空间 System.Net.Http 的静态类 HttpResponseHeadersExtensions 声明。

      • 如果找不到扩展方法,请尝试定位HttpResponseHeadersExtensions类。

      • 如果找不到 HttpResponseHeadersExtensions 类,请尝试升级 Web Api 2 库。升级每个项目的 WebApi2 的所有 nuget 包的最有效方法(对于像我这样讨厌升级 nuget 包的人)是对术语 'version="xxx" targetFramework="net45 的 .config 文件进行全局搜索/替换"'(其中 xxx 是旧版本,替换为 '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). &lt;code&gt; Set-Cookie: state1:name1=value1&amp;amp;name2=value2; state2:name3=value3&amp;amp;name4=value4; domain=domain1; path=path1; &lt;/code&gt;</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")); //headers 是一个 HttpResponseHeaders

      【讨论】:

      • 嗨@uzul,我的Headers 对象上没有AddCookies。有不同的命名空间吗?我的HttpAuthenticationContextSystem.Web.Http.Filters 命名空间的一部分。
      • 嗨@FrankO,确实,AddCookies 是一种扩展方法 :) 你只需要添加程序集 System.Net.Http.Formatting.dll
      • 好的。我有需要,但您的解决方案的问题是 authContext.ActionContext.Response 为空,如果我尝试在 IAuthenticationFilter 中使用 authContext.ActionContext.Response = new HttpResponseMessage(),控制器操作会在我使用 return Request.CreateReponse&lt;MyObj&gt;(myObj); 时覆盖它
      • 我以为我使用的是最新的 Web API? 2.2版?我想我现在必须使用 HttpContext.Current 并更改为基于令牌的方法。感谢您的帮助@uzul。
      • 我遇到了和 FrankO 一样的问题。 AuthenticationFilter 的 AuthenticateAsync 方法中的响应为空。我在 WebApi 2.2 上。如果不使用 HttpContext,应该如何设置 cookie?
      猜你喜欢
      • 2015-10-30
      • 2014-08-21
      • 2012-08-27
      • 1970-01-01
      • 2014-03-09
      • 1970-01-01
      • 1970-01-01
      • 2012-04-02
      • 1970-01-01
      相关资源
      最近更新 更多