C# Webapi获取承载令牌

C# Webapi获取承载令牌,c#,asp.net-web-api2,C#,Asp.net Web Api2,我正在使用asp.NETWebAPI进行练习,希望提供独立的授权服务 因此,我实现了基于令牌的授权服务(owin)和数据提供者服务。现在我想覆盖数据提供程序服务中的Authorize属性。它必须从当前请求中获取承载令牌,向授权服务发出请求,接收有关用户及其角色的信息 问题是:如何在我的自定义属性中获得不记名令牌,也许有更好的方法来进行这种“令牌转移” 我想这样使用它: //data service [CustomAttribute (Roles = "admin")] public IEnume

我正在使用asp.NETWebAPI进行练习,希望提供独立的授权服务

因此,我实现了基于令牌的授权服务(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;
}
//数据服务
[CustomAttribute(Roles=“admin”)]
公共IEnumerable Get()
{
返回新字符串[]{“value1”,“value2”};
}
公共类CustomAttribute:System.Web.Mvc.AuthorizeAttribute
{
授权时的公共覆盖无效(授权上下文)
{
使用(WebClient=newWebClient())
{
弦乐演奏者;
//不知怎么弄到了代币
客户。标题。添加(“授权”、“持票人”+持票人);
string userinfo=client.DownloadString(“authURL/GetUserInfo”);
CustomUser=JsonConvert.DeserializeObject(userinfo);
如果(!user.Roles==this.Roles)
{
//返回401
}
} 
}
}
//授权服务
公共异步任务GetUserInfo()
{ 
var owinContext=HttpContext.Current.GetOwinContext();
int userId=owinContext.Authentication.User.Identity.GetUserId();
var response=newuserinforesponse()
{
UserId=UserId.ToString(),
角色=等待UserManager.GetRolesAsync(用户ID)
}; 
返回响应;
}

要回答有关如何访问请求授权标头中的承载令牌的特定问题,请执行以下操作:

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!
            }
        } 
    }
}
公共类CustomAttribute:System.Web.Mvc.AuthorizeAttribute
{
授权时的公共覆盖无效(授权上下文)
{
System.Net.Http.Headers.AuthenticationHeaderValue authorizationHeader=context.HttpContext.Request.Headers.Authorization;
//检查HTTP请求中是否存在授权标头,以及该标头是否位于
//“授权:持票人”格式
if((authorizationHeader==null)| |(authorizationHeader.Scheme.CompareTo(“承载人”)!=0)| |(String.IsNullOrEmpty(authorizationHeader.Parameter)))
{
//未经授权返回HTTP 401
}
使用(WebClient=newWebClient())
{
client.Headers.Add(“Authorization”、“bearier”+authorizationHeader.Parameter);
string userinfo=client.DownloadString(“authURL/GetUserInfo”);
CustomUser=JsonConvert.DeserializeObject(userinfo);
如果(!user.Roles==this.Roles)
{
//我建议在这里返回HTTP403,而不是401
//请求已通过承载令牌进行身份验证,但
//经过身份验证的客户端没有足够的角色来执行
//请求,因此禁止他们这样做。HTTP 401未经授权
//这有点用词不当,因为实际意图是确定
//请求是否经过身份验证。HTTP 401还意味着
//应使用凭据重试该请求,但
//已经完成了!
}
} 
}
}

可能有更好的方法来完成您正在尝试做的事情,但我对MVC方面的事情以及应用程序的身份验证/授权工作流了解不够,因此无法提供一个很好的答案。至少这有助于知道在授权属性中从何处找到标题值。

正如Blair Allen所说,有更好的方法来完成我想要的。使用IdentityServer4生成令牌,只需检查令牌签名,无需任何其他请求。我切换到NetCore,这里是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");

}

你看过这个吗?承载令牌应与客户端一起存储,并随每个请求一起发送到数据提供程序。您所说的“自定义属性”是什么意思?我指的是System.Web.Mvc.AuthorizationAttribute,具有授权的重写方法(AuthorizationContext)
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,
    };
});