【问题标题】:ASP.Net Core 3 API always returns 401- JwtBearerASP.Net Core 3 API 总是返回 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 属性。很抱歉,我无法发现问题。

标签: c# asp.net-core jwt asp.net-core-webapi


【解决方案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() 方法中获得它的,但我假设它来自相同的设置文件。希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-09
    • 2018-04-03
    • 2020-05-05
    • 2018-07-01
    • 2011-03-12
    • 1970-01-01
    • 2020-03-28
    • 2013-02-26
    相关资源
    最近更新 更多