【问题标题】:Webapi get bearer tokenWebapi 获取不记名令牌
【发布时间】:2018-04-30 15:36:51
【问题描述】:

我在练习asp.net webapi,想做独立的授权服务。

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

问题是:如何在我的自定义属性中获取不记名令牌,也许有更好的方法来进行这种“令牌转移”?

我想这样使用它:

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

【问题讨论】:

  • 你看过这个吗? stackoverflow.com/questions/12629530/… Bearer 令牌应与客户端一起存储,并与每个请求一起发送给数据提供者。
  • “自定义属性”是什么意思?
  • 我的意思是 System.Web.Mvc.AuthorizeAttribute 具有重写方法 OnAuthorization(AuthorizationContext context)

标签: c# asp.net-web-api2


【解决方案1】:

回答您关于如何在请求的授权标头中访问不记名令牌的具体问题:

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 方面的事情以及您的应用程序的身份验证/授权工作流程了解得不够多,因此无法提供一个很好的答案。至少这应该有助于知道在哪里可以找到授权属性中的标头值。

【讨论】:

    【解决方案2】:

    正如布莱尔艾伦所难过的,有更好的方法来做我想做的事。使用 IdentityServer4 生成令牌,只需检查令牌签名,无需任何额外请求。我切换到net core,这里是mvc客户端的解决方案:receve token and save it in the 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,
        };
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-28
      • 2017-05-18
      • 2021-07-12
      • 2021-09-28
      • 2013-05-16
      • 2020-08-20
      • 2019-08-04
      相关资源
      最近更新 更多