首页 文章

从Web Api 2 IAuthenticationFilter AuthenticateAsync方法设置cookie

提问于
浏览
3

使用Web Api 2.2,我有一个自定义 IAuthenticationFilter ,用于通过自定义方案验证客户端请求 .

基本上,当客户端未经过身份验证并想要访问受保护资源时,他会在请求旁边发送 Authorization 标头: Authorization: MyCustomScheme XXXXXXX . 然后,过滤器验证凭据,对用户进行身份验证并生成无状态身份验证令牌以进一步访问(类似于JWT) .

我想将生成的身份验证令牌存储在cookie中 . 当存在于传入请求中时,cookie将在单独的过滤器中进行本地验证(此处未显示) .

我的问题是,如果我尝试像这样设置cookie:

Task IAuthenticationFilter.AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
    if (context.Request.Headers.Authorization != null &&
        string.Equals(context.Request.Headers.Authorization.Scheme, "MyCustomScheme", StringComparison.OrdinalIgnoreCase))
    {
        // This works
        CustomPrincipal principal = this.ValidateCredentials(context.Request.Headers.Authorization.Parameter);
        context.Principal = principal;

        // This doesn't work: context.ActionContext.Response is null
        var cookie = new CookieHeaderValue("MySessionCookie", principal.AuthenticationToken) { Path = "/", HttpOnly = true };
        context.ActionContext.Response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
    }
    return Task.FromResult(0);
}

然后它失败,因为 context.ActionContext.Response 为null . 如何在 AuthenticateAsync 内为响应添加cookie?

请参阅相关内容:Setting Cookie values in HttpAuthenticationContext for IAuthenticationFilter(您可以在评论中看到人们遇到同样的问题) .

3 回答

  • 1

    除了 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();
    
        // If the user is authenticated and the token is not present in the request cookies, then it needs to be set
        CustomPrincipal principal = actionContext.ControllerContext.RequestContext.Principal as CustomPrincipal;
        if (principal != null && !actionContext.Request.Headers.GetCookies("MySessionCookie").Any())
        {
            // Set the cookie in the response
            var cookie = new CookieHeaderValue("MySessionCookie", principal.AuthenticationToken) { Path = "/", HttpOnly = true };
            response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
        }
    
        return response;
    }
    

    我发现这个方法非常不实用(混合接口),你绝对应该可以访问 IAuthenticationFilter.AuthenticateAsync 中的响应(通过例如异步延续回调,或者通过能够在上下文中访问动作结果( IHttpActionResult ),如 ChallengeAsync 同一界面的方法) .

  • 0

    我的要求是添加 Headers ,但应该很容易适应添加cookie .

    我对此采取了不同的方法 . 我把我想添加的 Headers 添加到 context.Request.Properties 中 . 然后在 ChallengeAsync (它被调用每个请求,无论如何)通过 IHttpActionResult 我检查是否存在属性,如果存在则将其添加到 Headers 中 . 像这样的东西:

    protected class AddRenewOnAauthorizedResult : IHttpActionResult {
    
        public const string RenewalPropertyKey = "ETicket.RenewalKey";
    
        public AddRenewOnAauthorizedResult(HttpRequestMessage request, IHttpActionResult innerResult) {
            this.Request = request;
            this.InnerResult = innerResult;
        }
    
        public HttpRequestMessage Request { get; set; }
        public IHttpActionResult InnerResult { get; set; }
    
        public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
    
            HttpResponseMessage response = await this.InnerResult.ExecuteAsync(cancellationToken);
    
            if (Request.Properties.ContainsKey(RenewalPropertyKey)) Request.response.Headers.Add("X-ETicket-Renew", Request.Properties(RenewalPropertyKey));
    
            Return response;
    
    }
    

    }

    然后在 ChallengeAsync

    public Threading.Tasks.Task ChallengeAsync(HttpAuthenticationChallengeContext context, Threading.CancellationToken cancellationToken)
    {
    
        context.Result = new AddRenewOnAauthorizedResult(context.Request, context.Result);
        return Task.FromResult(0);
    
    }
    
  • 1

    您可能需要实现IRequiresSessionState才能使Cookie保持不变?

    见:http://www.strathweb.com/2012/11/adding-session-support-to-asp-net-web-api/

相关问题