ASP.Net Core 3.0 JWT Bearer Token 没有 SecurityTokenValidator 可用

Posted

技术标签:

【中文标题】ASP.Net Core 3.0 JWT Bearer Token 没有 SecurityTokenValidator 可用【英文标题】:ASP.Net Core 3.0 JWT Bearer Token No SecurityTokenValidator available 【发布时间】:2019-10-18 20:26:59 【问题描述】:

我使用 ASP.Net Core 3.0 API 和 EntityFramework Core 作为 UserStorage。 启动.cs:

        public void ConfigureServices(IServiceCollection services)
            
             using Microsoft.AspNetCore.Authentication.JwtBearer;
             using Microsoft.AspNetCore.Builder;
             using Microsoft.AspNetCore.Hosting;
             using Microsoft.AspNetCore.Identity;
             using Microsoft.AspNetCore.SpaServices.AngularCli;
             using Microsoft.EntityFrameworkCore;
             using Microsoft.Extensions.Configuration;
             using Microsoft.Extensions.DependencyInjection;
             using Microsoft.Extensions.Hosting;
             using Microsoft.IdentityModel.Tokens;
             using System;
             using System.Collections.Generic;
             using System.Linq;
             using System.Text;
             using System.Threading.Tasks;
                .
                .
                .

                //Add Identity Provider with EntityFramework
                services.AddIdentity<User, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDBContext>()
                .AddDefaultTokenProviders();

                //Initialize EntityFramework
                services.AddDbContext<ApplicationDBContext>(options => options.UseSqlite(Configuration.GetConnectionString("localDB")));

                //Initialize JWT Authentication
                services.AddAuthentication(options => 
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                ).AddJwtBearer(jwtBearerOptions =>
                
                    jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
                    
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,

                        ValidIssuer = "http://localhost:44352",
                        ValidAudience = "http://localhost:44352",
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("Secrets")["jwt"]))
                    ;
                
                );
                services.AddMvc(options => options.EnableEndpointRouting = false)
                    .AddNewtonsoftJson();

                // In production, the Angular files will be served from this directory
                services.AddSpaStaticFiles(configuration =>
                
                    configuration.RootPath = "ClientApp/dist";
                );
            

            .
            .
            .


                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseSpaStaticFiles();

                //Enable Authentication
                app.UseAuthentication();
                app.UseAuthorization();

                .
                .
                .

                app.UseMvc(routes =>
                
                    routes.MapRoute(
                        name: "default",
                        template: "controller/action=Index/id?");
                );


    .
    .
    .

这是我发出 JWT 令牌的代码:


public async Task<IActionResult> Login()
        
            using (var reader = new StreamReader(Request.Body))
            
                var body = await reader.ReadToEndAsync();
                var cred = JsonConvert.DeserializeObject<Credentials>(body);
                var result = (await userService.LoginUser(cred.userName, cred.password));
                if (result == 200)
                

                    var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration.GetSection("Secrets")["jwt"]));
                    var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256Signature);

                    var roles = await userService.GetRoleFromUsername(cred.userName);
                    var rolesString = JsonConvert.SerializeObject(roles);

                    var tokeOptions = new JwtSecurityToken(
                                issuer: "http://localhost:44352",
                                audience: "http://localhost:44352",
                                claims: new List<Claim>(new List<Claim> 
                                        new Claim("userName",cred.userName),
                                        new Claim("roles", rolesString)
                                ),
                                expires: DateTime.Now.AddHours(1),
                                signingCredentials: signinCredentials
                    );

这是我使用授权的 API 调用:


[Route("api/videos/add")]
[Authorize(Roles = "Admin")]
[HttpPost]
public async Task<IActionResult> AddVideo()

    using (var reader = new StreamReader(Request.Body))
    
        var body = await reader.ReadToEndAsync();
        var video = JsonConvert.DeserializeObject<Video>(body);
        await videoService.AddVideo(video);
        return Ok();
    


我的 NuGet 包是:

Microsoft.EntityFrameworkCore 3.0.0-preview5.19227.1 Microsoft.EntityFrameworkCore.Sqlite 3.0.0-preview5.19227.1 Microsoft.AspNetCore.Authentication.JwtBearer 3.0.0-preview4-19216-03 Microsoft.EntityFrameworkCore.Sqlite.Core 3.0.0-preview5.19227.1 Microsoft.NETCore.Platforms 3.0.0-preview4.19212.13 Microsoft.AspNetCore.Mvc.NewtonsoftJson 3.0.0-preview5-19227-01 Microsoft.AspNetCore.SpaServices.Extensions 3.0.0-preview5-19227-01 Microsoft.AspNetCore.Identity.EntityFrameworkCore 3.0.0-preview5-19227-01 runtime.win-x64.Microsoft.NETCore.DotNetAppHost 3.0.0-preview4-27615-11

我遇到的问题是,如果我调用那个 API 部分,我会收到错误:

信息:承载未通过身份验证。失败消息:没有可用于令牌的 SecurityTokenValidator:

任何帮助将不胜感激,因为我找不到错误

【问题讨论】:

你可以试试这个link 感谢您的回答。不幸的是,我不使用 OpenID Connect 没有“普通”的方式来完成这个吗? 在声明列表中使用 ClaimTypes.Role 而不是 "roles"rolesString的内容是什么? 感谢您的回答。 rolesString的内容是一个List,通过JsonConvert.SerializeObject()转换成字符串 【参考方案1】:

如果您想添加角色作为声明,请尝试使用ClaimTypes.Role 而不是roles

var tokeOptions = new JwtSecurityToken(
                            issuer: "http://localhost:44352",
                            audience: "http://localhost:44352",
                            claims: new List<Claim>(new List<Claim> 
                                    new Claim("userName",cred.userName),
                                    new Claim(ClaimTypes.Role, "Admin")                                      
                            ),
                            expires: DateTime.Now.AddHours(1),
                            signingCredentials: signinCredentials
                );

【讨论】:

感谢您的回答。不幸的是,这并没有做到。我仍然遇到同样的错误 当我用 postman 测试时,它在我的 asp.net core 2.2 项目中运行良好。你如何测试 api? 我正在使用我正在开发的 Angular7 SPA 进行测试【参考方案2】:

感谢邹星,我找到了错误的根源。问题是我用引号发送了不记名令牌。

现在API中的错误消失了,问题是现在API中的授权失败并返回403。

编辑:

我发现了有关错误 403 的问题。似乎您只能在承载令牌中发送一个角色以供 ASP.Net 验证它。 userManager.GetRolesAsync 的返回类型表明用户可以拥有多个角色,这些角色可以包含在 JWT 不记名令牌中。

这意味着我的问题已解决。

我要感谢大家的回答。没有你,我不会得到它!

【讨论】:

【参考方案3】:

我是这样处理这个问题的:

client.DefaultRequestHeaders.Add("Authorization", $"Bearer token.Replace("\"", "")");

不是最好的解决方案,但确实有效。

【讨论】:

以上是关于ASP.Net Core 3.0 JWT Bearer Token 没有 SecurityTokenValidator 可用的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core JWT 和声明

如何将 JWT 用于 asp.net Core

JWT+ASP.NET Core集成方案

asp.net core + angular2 JWT 承载

ASP.NET Core JWT 身份验证受众属性

ASP.NET Core 2 授权属性 jwt