ASP.Net Core 3 API 总是返回 401- JwtBearer

Posted

技术标签:

【中文标题】ASP.Net Core 3 API 总是返回 401- JwtBearer【英文标题】:ASP.Net Core 3 API always returns 401- JwtBearer 【发布时间】:2020-05-27 09:26:05 【问题描述】:

我有一个 ASP .NET Core WebAPI,我生成了一个 JWT 令牌用于授权,但每当我发送请求时,我都会收到 401 - Unauthorized

操作顺序:

     1. GET for token
     2. GET for user <-- 401

我在 jwt.io 上检查了我的令牌,它是正确的。 当我删除 [Authorize] 属性时一切正常

Startup.cs

   public void ConfigureServices(IServiceCollection services)
        
            IdentityModelEventSource.ShowPII = true;
            var appSettingsSection = Configuration.GetSection("Jwt");
            services.Configure<JwtSettings>(appSettingsSection);
            var appSettings = appSettingsSection.Get<JwtSettings>();
            services.AddControllers();
            services.AddOptions();

            services.AddAuthentication(x => 
            
                x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
               
            )
            .AddJwtBearer(x=>
            
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                
                    ValidateIssuerSigningKey = true,
                    ValidateIssuer = true,
                    ValidateLifetime = true,
                    ValidAudience = appSettings.Issuer,
                    ValidIssuer = appSettings.Issuer,
                    ValidateAudience = false,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.Key))
                ;

            
            );
        



  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            app.UseRouting();
            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllers();

            );
        

CreateToken 方法

 public JwtDto CreateToken(string email, string role)
        
            var now = DateTime.UtcNow;
            var claims = new Claim[]
            
                new Claim(JwtRegisteredClaimNames.Sub,email),
                new Claim(ClaimTypes.Role, role),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Iat,now.ToTimestamp().ToString(),ClaimValueTypes.Integer64)
            ;

            
            var expires = now.AddMinutes(360);
            var singingCredentails = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.Key)),SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: _settings.Issuer,
                claims: claims,
                notBefore: now,
                expires: expires,
                signingCredentials: singingCredentails
            );
            var token = new JwtSecurityTokenHandler().WriteToken(jwt);

            return new JwtDto
            
                Token = token,
                Expiry = expires.ToTimestamp()
            ;
        

GetToken - API

[HttpGet]
[Route("token")]
public IActionResult GetToken()

    var token = _jwtHandler.CreateToken("test", "user");
    return Json(token);

GetUser - API

    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    [HttpGet("email")]
    public async Task<UserDto> Get(string email)
    
      return  await _userService.GetUserAsync(email);
    

【问题讨论】:

您知道您对 GetUser 的调用有一个格式正确的 Authorization 标头,其中包含令牌? "授权:承载 " 来自调试输出的消息:Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息:授权失败。 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:信息:AuthenticationScheme:Bearer 被质询。 但我的意思是您的客户端(JS 应用程序/邮递员?)正在发送正确的 Auth 标头?如果请求中没有正确的 auth 标头,那么您将始终得到 401。对于测试,使用 Postman 效果很好,并且可以让您对请求进行大量控制。 是的,我发送了一个带有 Auth 标头的请求。您可以在这里找到我的代码:github.com/leavinus/GetARide/tree/jwt_problem/GetARide.Api 我为测试创建了 .REST 文件 :) 将您的代码与我使用的一些代码进行比较时,它们几乎相同,除了我使用 Auth 策略(启动时的 services.AddAuthorization())并且您使用 Authorize 属性。很抱歉,我无法发现问题。 【参考方案1】:

我遇到了完全相同的问题,并且认为问题出在 Startup.cs 中的 Configure() 方法中。您有正确的 UseAuthentication() 和 UseAuthorization() 调用,顺序正确,这很重要,也是我发现的问题。因此,对您而言,我认为问题在于缺少 UseCors() 调用。我的工作启动类如下:

public class Startup

    private bool _isDevelopmentEnvironment = true;
    public IConfiguration configuration  get; 

    public Startup(IConfiguration configuration)
    
        this.configuration = configuration;
    

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    
        services.AddControllers();

        // Retrieve App Settings:
        var appSettingsSection = configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);
        var appSettings = appSettingsSection.Get<AppSettings>();

        // Configure JWT:
        var key = Encoding.ASCII.GetBytes(appSettings.JwtSharedSecret);
        services.AddAuthentication(x =>
        
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        )
        .AddJwtBearer(x =>
        
            x.RequireHttpsMetadata = !_isDevelopmentEnvironment;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = appSettings.JwtValidateIssuer,
                ValidateAudience = appSettings.JwtValidateAudience,
                ValidateLifetime = appSettings.JwtValidateLifetime,
                ClockSkew = TimeSpan.Zero
            ;
        );

        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IUserService, UserService>();
        services.AddScoped<IHydrator<User, UserModel>, UserModelHydrator>();
    

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
        
        else
        
            _isDevelopmentEnvironment = false;
            app.UseHsts();
        

        app.UseHttpsRedirection();

        app.UseRouting();

        // TODO: Adjust CORS settings appropriately
        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        
            endpoints.MapControllers();
        );
    

我还确认令牌生成代码和 Startup.cs 代码都使用应用程序设置中的相同密钥,我看不出您是如何在 CreateToken() 方法中获得它的,但我假设它来自相同的设置文件。希望这会有所帮助!

【讨论】:

以上是关于ASP.Net Core 3 API 总是返回 401- JwtBearer的主要内容,如果未能解决你的问题,请参考以下文章

每当我发送包含 Bearer 令牌的请求时,ASP.Net Core API 总是返回 401 未授权

IFormFile 在 asp.net core 2.1 中总是返回 null

ASP.NET Core Identity 3.1:UserManager.RemoveFromRoleAsync 总是返回 UserNotInRole

Blazor ASP.Net Core 3.1 Web API 在发布时返回 404 错误

ASP.NET Core 3.1 MVC JWT 登录返回 401

在 HTTPS 上使用 Windows 身份验证首次调用 ASP.NET Core 2.0 Web API 在 Chrome 中总是失败