设置cookie从Web Api 2 IAuthenticationFilter AuthenticateAsync方法

本文关键字:IAuthenticationFilter AuthenticateAsync 方法 Api cookie Web 设置 | 更新日期: 2023-09-27 18:07:01

使用Web Api 2.2,我有一个自定义IAuthenticationFilter,用于使用自定义方案对客户机请求进行身份验证。

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

我想将结果身份验证令牌存储在cookie中。当传入请求中存在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为空。如何将cookie添加到AuthenticateAsync内的响应中?

参见相关内容:为IAuthenticationFilter在HttpAuthenticationContext中设置Cookie值(你可以在评论中看到人们遇到同样的问题)。

设置cookie从Web Api 2 IAuthenticationFilter AuthenticateAsync方法

我的要求是添加一个标题,但它应该很容易适应添加cookie。

我对此采取了不同的方法。我把我想要添加到context.Request.Properties的标题。然后在ChallengeAsync(无论如何它都会被调用)通过IHttpActionResult我检查属性的存在,如果它存在,将其添加到标题中。像这样:

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;
}

}

Then in ChallengeAsync:

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

除了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方法中一样)。

你可能需要实现IRequiresSessionState让cookie持久?

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

相关文章:
  • 没有找到相关文章