在 ASP .Net Core 2.2 中添加 JWT 令牌后授权不起作用

Posted

技术标签:

【中文标题】在 ASP .Net Core 2.2 中添加 JWT 令牌后授权不起作用【英文标题】:Authorization does not work after adding JWT token in ASP .Net Core 2.2 【发布时间】:2020-02-27 16:52:25 【问题描述】:

我正在学习如何在 ASP 中使用 JWT 令牌认证。我有一个简单的网站,其中包含 CRUD 操作和一个存储库,我添加了注册/登录功能,并且我有一个名为“管理员”的超级用户角色。通常,这是我检查用户当前是否以管理员身份登录的方式:

bool admin = User.IsInRole(Constants.ADMIN_ROLE);

在我将 JWT 身份验证添加到我的应用程序之前,此功能运行良好。现在,使用我的管理员帐户(手动添加到数据库)登录,我从来没有得到正确的值。当我尝试查询用户时,我得到 NULL:

var user = await _userManager.GetUserAsync(HttpContext.User)

这是我在 Startup.cs 中的 ConfigureServices:

public void ConfigureServices(IServiceCollection services)
    
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddIdentity<MyUser, MyRole>()
            .AddEntityFrameworkStores<MyContext>()
            .AddRoles<MyRole>();


        services.AddDbContext<MyContext>(builder =>
        
            builder.UseSqlServer(Configuration["ConnectionStrings"]);
        );

        // repo code here ommitted for clarity

        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);

        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);
        services.AddAuthentication(x =>
        
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        )
        .AddJwtBearer(x =>
        
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
            ;

        );

    

这是我的配置类:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
    
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
        
        else
        
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        

        app.UseHttpsRedirection();
        app.UseAuthentication();
        app.UseMvc();
        app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
    

据了解,由于 JWT 是身份验证,它根本不应该影响授权,所以我想我忘了使用一些额外的选项,但我似乎找不到什么。任何帮助表示赞赏!

【问题讨论】:

【参考方案1】:

我最终完全在 JWT 中实现了身份验证。

在创建令牌描述符期间,我在令牌内添加了一个新的用户声明:

                  ... 
 Subject = new ClaimsIdentity(new Claim[]
            
                new Claim(ClaimTypes.Name, userId.ToString()),
                new Claim(ClaimTypes.Role, roleId)
            ),
                  ...

并添加与内部角色相关的信息(在我的例子中,我使用了角色的 ID 以使其不那么具有描述性,以防有人设法破译它)

var roles = await _userManager.GetRolesAsync(userInDb);
var userRoleId = await _roleManager.FindByNameAsync(roles.First());
                       ...
return Ok(_tokenService.GenerateToken(userInDb.Id, userRoleId.Id.ToString()));

然后,确定用户是否为管理员就像从令牌中获取适当的值一样简单:

private async Task<bool> IsUserAdmin()

    var roleId = Guid.Parse(User.Claims.FirstOrDefault(e => e.Type == "role").Value);
    var adminId = (await _roleManager.FindByNameAsync(Constants.ADMIN_ROLE))?.Id;     
    return roleId == adminId;

虽然这似乎可行,但我仍然认为可能有更好(不那么 hacky)的方法可以更好地将 JWT 集成到身份中,所以如果有人可以提出更简洁的解决方案,我很乐意接受它作为回答而不是我的解决方案。

【讨论】:

以上是关于在 ASP .Net Core 2.2 中添加 JWT 令牌后授权不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET Core 2.2 中实现标识

如何在asp.net core razor pages 2.2中设置日期格式和文化

获取 ASP.NET-Core 2.2 控制器中的控制器名称和方法名称

如何在 ASP.NET Core 2.2 中使用 IValidateOptions 验证配置设置?

ASP.NET Core Identity UserManager.IsInRole 调用在 2.2 中有效,但在 3.0 中引发 InvalidOperation

在 Razor (chtml) 中渲染动态视图,如何在 asp.net core 3.0 中将 FileProvider 添加到 razor?