授权令牌在ASP.NET Core中未绑定

时间:2018-09-12 22:19:42

标签: c# asp.net-core

我正在这样调用REST api:

HttpClient client;
var uri = new Uri(Const.GetUserAccount);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("accessToken", App.AccessToken);
var response = await client.GetAsync(uri);

这是我的动作签名(accessToken为null):

public async Task<ActionResult> GetAccountAsync([FromHeader] string accessToken)

令牌位于Request.Headers.HeaderAuthorization中,其值为:

"accessToken" + a space + the guid

这似乎很奇怪。不应该有一个名称/值对吗?喜欢:

“ accessToken”:“ theGUID”

这就是为什么它不具有约束力吗?如果是这样,如何正确通过?如果没有,我在做什么错了?

1 个答案:

答案 0 :(得分:2)

  

这就是为什么它不具有约束力吗?

原因是您的操作方法要求请求标头中有accessToken

public async Task<ActionResult> GetAccountAsync([FromHeader] string accessToken)

尽管您在请求中没有这样的AccessToken: xxx_yyy_zzz标头。

如果您发送如下请求:

GET https://localhost:44323/api/values/account HTTP/1.1
accessToken : xxx_yyy_zzz

ModelBinder将绑定accessToken

  

如果是,我如何正确通过?

我不确定为什么要在动作方法中使用accessToken。但是,如果您确实需要通过模型绑定来访问令牌,则至少有两种方法可以做到这一点:

一种方法是更改​​操作方法,以直接获取Authorization标头:

public async Task<ActionResult> GetAccount2Async([FromHeader] string authorization) 
{
    if (String.IsNullOrEmpty(authorization)) { /* */ }
    if (!authorization.StartsWith("accessToken",StringComparison.OrdinalIgnoreCase)) { /* */ }

    var token = authorization.Substring("accessToken".Length).Trim();
    // ...
}

当您发送标头为Authorization : accessToken xxx_yyy_zzz的请求时,它将起作用。

但是,上述方法不是很好且干净的方法。更好的方法是创建自定义ModelBinder

首先,我们创建一个虚拟类来保存accessToken值:

public class AccessTokenAuthorizationHeader
{
    public string TokenValue { get; set; }
}

这是一个简单的模型绑定程序,它将从标头中检索访问令牌:

public class AuthorizationHeaderBinder : IModelBinder
{
    const string DEFAULT_ACCESS_TOKEN_AUTH_HEADER_PREFIX = "accessToken";
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); }

        var modelName = bindingContext.BinderModelName;
        if (string.IsNullOrEmpty(modelName)) { modelName = DEFAULT_ACCESS_TOKEN_AUTH_HEADER_PREFIX; }

        var authorization = bindingContext.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
        if (String.IsNullOrWhiteSpace(authorization)) {
            return Task.CompletedTask;
        }
        if (!authorization.StartsWith(modelName, StringComparison.OrdinalIgnoreCase)) {
            return Task.CompletedTask;
        }
        var token = authorization.Substring(modelName.Length).Trim();

        bindingContext.Result = ModelBindingResult.Success(new AccessTokenAuthorizationHeader() {
            TokenValue =token,
        });
        return Task.CompletedTask;
    }
}

最后,用AccessTokenAuthorizationHeader装饰前一个ModelBinderAttribute

[ModelBinder(BinderType =typeof(AuthorizationHeaderBinder))]
public class AccessTokenAuthorizationHeader
{
    public string TokenValue { get; set; }
}

现在我们可以自动绑定它:

[HttpGet("Account3")]
public async Task<ActionResult> GetAccount3Async(AccessTokenAuthorizationHeader accessToken) {
    var result =new JsonResult(accessToken?.TokenValue);
    return result;
}

让我们用requset进行测试:

GET https://localhost:44323/api/values/account3 HTTP/1.1
Authorization : accessToken 111111

响应将是:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcOVw5LTEzXFNPLkF1dGhvcml6YXRpb25IZWFkZXJcQXBwXEFwcFxhcGlcdmFsdWVzXGFjY291bnQz?=
X-Powered-By: ASP.NET
Date: Thu, 13 Sep 2018 01:54:25 GMT

"111111"