C# .Net Core 2 JWT、Angular 2角色授权不起作用

C# .Net Core 2 JWT、Angular 2角色授权不起作用,c#,asp.net-core-mvc,jwt,asp.net-core-2.0,angular2-jwt,C#,Asp.net Core Mvc,Jwt,Asp.net Core 2.0,Angular2 Jwt,我在JWT生成的令牌中有以下有用的负载 { “分包商”:flamelsoft@gmail.com", “jti”:“0bca1034-f3ce-4f72-bd91-65c1a61924c4”, “”:“管理员”, “经验”:1509480891, “iss”:“, “澳元”:” } 使用此代码 Startup.cs public void ConfigureServices(IServiceCollection services) { services.A

我在JWT生成的令牌中有以下有用的负载

{ “分包商”:flamelsoft@gmail.com", “jti”:“0bca1034-f3ce-4f72-bd91-65c1a61924c4”, “”:“管理员”, “经验”:1509480891, “iss”:“, “澳元”:” }

使用此代码 Startup.cs

        public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DBContextSCM>(options =>
        options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), b =>
         b.MigrationsAssembly("FlamelsoftSCM")));

        services.AddIdentity<User, Role>()
            .AddEntityFrameworkStores<DBContextSCM>()
            .AddDefaultTokenProviders();

        services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

        services.AddAuthentication()
             .AddJwtBearer(cfg =>
             {
                 cfg.RequireHttpsMetadata = false;
                 cfg.SaveToken = true;

                 cfg.TokenValidationParameters = new TokenValidationParameters()
                 {
                     ValidIssuer = Configuration["Tokens:Issuer"],
                     ValidAudience = Configuration["Tokens:Issuer"],
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
                 };

             });

        services.AddMvc();
    }
问题是角色的验证不起作用,请求到达控制器并在头中返回代码200,但从未进入类。 当我删除[Authorize(Roles=“Administrator”)]时,它会正确输入我的代码。 有什么定义不清的吗?或者,通过角色定义授权的替代方法是什么。

TL;博士

如原问题评论中所述,更改为:

[HttpPost]
[授权(角色=“管理员”)]
公共异步任务寄存器([FromBody]寄存器模型)
{
//代码
}

[HttpPost]
[授权(AuthenticationSchemes=“承载人”,Roles=“管理员”)]
公共异步任务寄存器([FromBody]寄存器模型)
{
//代码
}
解决了这个问题

承载
是在ASP.NET核心中使用JWT承载身份验证时的首选


但是为什么我们需要在
[Authorize]
属性上指定
AuthenticationSchemes
属性呢

这是因为配置身份验证方案并不意味着它们将在每个HTTP请求上运行。如果匿名用户可以访问特定的操作,为什么还要从cookie或令牌中提取用户信息呢?MVC在这方面很聪明,只会在需要时运行身份验证处理程序,也就是说,在某种程度上受到保护的请求期间运行身份验证处理程序

在我们的例子中,MVC发现了
[Authorize]
属性,因此知道它必须运行身份验证和授权来确定请求是否被授权。诀窍在于它将只运行已指定的。在这里,我们没有身份验证,因此没有执行身份验证,这意味着授权失败,因为请求被认为是匿名的

向属性添加身份验证方案指示MVC运行该处理程序,该处理程序从HTTP请求中的令牌中提取用户信息,从而发现
管理员
角色,请求被允许


作为补充说明,还有另一种方法可以实现这一点,而无需使用
[Authorize]
属性的
AuthenticationSchemes
属性

假设您的应用程序只配置了一个身份验证方案,那么在每个
[Authorize]
属性上指定
authorizationschemes
属性将是一件痛苦的事情

使用ASP.NET Core,您可以配置默认身份验证方案。这样做意味着将为每个HTTP请求运行关联的处理程序,而不管资源是否受到保护

此设置分两部分进行:

公共类启动
{
public void配置服务(IServiceCollection服务)
{
服务
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme/*设置默认的身份验证方案*/)
.AddJwtBearer(选项=>
{
//在此处配置选项
});
}
公共void配置(IApplicationBuilder应用程序)
{
//这将插入将执行
//每个请求上的默认身份验证方案处理程序
app.UseAuthentication();
app.UseMvc();
}
}
这样做意味着,当MVC评估请求是否被授权时,身份验证已经发生,因此不为
[Authorize]
属性的
AuthenticationSchemes
属性指定任何值将不会成为问题


流程的授权部分仍将运行,并根据已验证的用户检查他们是否属于
管理员组。

我知道这个问题已经有了答案,但这里遗漏了一些重要的内容。您需要确保您正在为登录用户实际设置声明。在我的例子中,我使用的是JWT身份验证,因此这一步非常重要:

    var claims = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, user.UserName) });
    var roles = await _userManager.GetRolesAsync(user);
    if (roles.Count > 0)
    {
        foreach (var role in roles) { claims.AddClaim(new Claim(ClaimTypes.Role, role)); }
    }

    var token = new JwtSecurityToken(
        issuer: _configuration["JWT:Issuer"],
        audience: _configuration["JWT:Audience"],
        expires: DateTime.UtcNow.AddMinutes(15),
        signingCredentials: signingCredentials,
        claims: claims.Claims);
我绞尽脑汁想弄明白为什么
HttpContext.User
没有包括我希望缩小
[authorization(Roles=“Admin”)]
问题范围的内容。事实证明,如果您使用的是JWT Auth,则需要记住将
声明[]
设置为标识。也许这是通过其他
dotnet
方式自动完成的,但是
jwt
似乎需要您手动设置


在我为用户设置声明后,
[Authorize(Roles=“Whatever”)]
按预期工作。

我认为第一步是确定失败的是身份验证还是授权。您能否将
[Authorize(Roles=“Administrator”)]
替换为
[Authorize]
?这将强制用户成功通过身份验证,但不要求他们是
管理员
角色的一部分。根据结果,我们将决定下一步查看的位置。如果我将[Authorize(Roles=“Administrator”)]替换为[Authorize],则正确。我认为问题如下。找不到声明/角色URI。知道如何修复它吗?我建议您使用JWT中间件事件来检查从令牌生成的
ClaimsPrincipal
JwtBearerOptions
公开了一个
Events
属性,该属性允许您在身份验证过程的不同阶段挂接一些逻辑。身份验证成功后,将调用
TokenValidated
方法。检查生成委托人的索赔并给出结果。非常感谢,解决方案如下,
[authorize]
export class UserService {

constructor(private http: Http, private config: AppConfig, private currentUser: User) { }

create(user: User) {
    return this.http.post(this.config.apiUrl + 'Account/Register', user, this.jwt());
}

private jwt() {
    const userJson = localStorage.getItem('currentUser');
    this.currentUser = userJson !== null ? JSON.parse(userJson) : new User();

    if (this.currentUser && this.currentUser.token) {
        let headers = new Headers({ 'Authorization': 'Bearer ' + this.currentUser.token });
        return new RequestOptions({ headers: headers });
    }
}}
    var claims = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, user.UserName) });
    var roles = await _userManager.GetRolesAsync(user);
    if (roles.Count > 0)
    {
        foreach (var role in roles) { claims.AddClaim(new Claim(ClaimTypes.Role, role)); }
    }

    var token = new JwtSecurityToken(
        issuer: _configuration["JWT:Issuer"],
        audience: _configuration["JWT:Audience"],
        expires: DateTime.UtcNow.AddMinutes(15),
        signingCredentials: signingCredentials,
        claims: claims.Claims);