WebAPI获取Bearer令牌

8

我正在练习使用asp.net webapi,并希望创建一个独立的授权服务。

因此,我基于令牌(owin)和数据提供程序服务实现了授权服务。现在,我想覆盖数据提供程序服务中的Authorize属性。它必须从当前请求获取Bearer令牌,向授权服务发送请求,接收有关用户及其角色的信息。

问题是:如何在自定义属性中获取Bearer令牌,而且可能有更好的方法来进行这种“令牌传递”?

我希望像这样使用它:

//data service
[CustomAttribute (Roles = "admin")]
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}



public class CustomAttribute : System.Web.Mvc.AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext  context)
    {
        using (WebClient client = new WebClient())
        {
            string bearerToken;
            //somehow get token
            client.Headers.Add("Authorization", "Bearer " + bearerToken);
            string userinfo = client.DownloadString("authURL/GetUserInfo");
            CustomUser user = JsonConvert.DeserializeObject<CustomUser>(userinfo);
            if (!user.Roles == this.Roles)
            {
                    //return 401
            }
        } 
    }
}


// authorization service
public async Task<UserInfoResponse> GetUserInfo()
{ 
    var owinContext = HttpContext.Current.GetOwinContext();
    int userId = owinContext.Authentication.User.Identity.GetUserId<int>();
    var response = new UserInfoResponse()
    {
        UserId = userId.ToString(),
        Roles = await UserManager.GetRolesAsync(userId)
    }; 
    return response;
}

1
你看过这个吗?https://dev59.com/pmcs5IYBdhLWcg3wtmSf Bearer token 应该与客户端一起存储,并在每个请求发送到数据提供者时发送。 - Dan Wilson
“Custom attribute” 是什么意思? - Dai
我指的是System.Web.Mvc.AuthorizeAttribute,其中包含重写方法OnAuthorization(AuthorizationContext context)。 - Alex White
2个回答

3
回答你具体的问题,关于如何访问请求中授权头部的Bearer令牌:
public class CustomAttribute : System.Web.Mvc.AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext context)
    {
        System.Net.Http.Headers.AuthenticationHeaderValue authorizationHeader = context.HttpContext.Request.Headers.Authorization;

        // Check that the Authorization header is present in the HTTP request and that it is in the
        // format of "Authorization: Bearer <token>"
        if ((authorizationHeader == null) || (authorizationHeader.Scheme.CompareTo("Bearer") != 0) || (String.IsNullOrEmpty(authorizationHeader.Parameter)))
        {
            // return HTTP 401 Unauthorized
        }

        using (WebClient client = new WebClient())
        {
            client.Headers.Add("Authorization", "Bearer " + authorizationHeader.Parameter);
            string userinfo = client.DownloadString("authURL/GetUserInfo");
            CustomUser user = JsonConvert.DeserializeObject<CustomUser>(userinfo);
            if (!user.Roles == this.Roles)
            {
                    // I recommend return HTTP 403 Forbidden here, not 401. At this point
                    // the request has been authenticated via the bearer token, but the
                    // authenticated client does not have sufficient roles to execute the
                    // request, so they are forbidden from doing so. HTTP 401 Unauthorized
                    // is a bit of a misnomer because the actual intention is to determine
                    // whether or not the request is authenticated. HTTP 401 also implies
                    // that the request should be tried again with credentials, but that
                    // has already been done!
            }
        } 
    }
}

可能有更好的方法来完成你想做的事情,但我不太了解MVC方面和你应用程序的身份验证/授权工作流程,因此无法提供一个好的答案。至少这可以帮助你知道在授权属性内如何找到头部值。


0
正如Blair Allen所说,有更好的方法来实现我想要的功能。使用IdentityServer4生成令牌,只需检查令牌签名,无需进行任何其他请求。我已经切换到了net core,并为mvc客户端提供了解决方案:接收令牌并将其保存在cookie中。
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
    if(!ModelState.IsValid)
    {
        return View(model);
    }

    var tokenResult = await AuthService.LoginUserAsync(model.Email, model.Password);
    if(!tokenResult.IsSuccess)
    {
        ModelState.AddModelError("","Wrong email or password");
        return View(model);

    }

    Response.Cookies.Append("access_token", tokenResult.AccessToken, new CookieOptions(){
        HttpOnly = true,
        SameSite = SameSiteMode.Strict,
        Secure = true
    });

    return RedirectToAction("Index", "Home");

}

然后只需使用

services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, config =>
{
    config.Authority = configuration["TokenServerUrl"];
    config.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var token = context.HttpContext.Request.Cookies["access_token"];
            context.Token = token;
            return Task.CompletedTask;

        },

    };
    config.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = configuration["TokenServerUrl"],
        ValidateLifetime = true,
    };
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接