简体   繁体   中英

ASP.Net Core 3 API always returns 401- JwtBearer

I have an ASP .NET Core web api and I generate a JWT token for authorization purposes but whenever I shoot request I get 401 - Unauthorized .

The order of operations:

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

I checked my token on jwt.io and it was correct. When I remove [Authorize] attrivute everything works fine

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 method

 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 <---------- 401 error

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

Token request

I have come across the exact same problem and believe the issue is in the Configure() method in Startup.cs. You have the correct UseAuthentication() and UseAuthorization() calls, in the correct order, which is important, and was the problem I discovered. For you therefore I think the problem is the lack of the UseCors() call. My working Startup class is below:

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();
        });
    }
}

I also confirmed that both the token generation code and the Startup.cs code use the same key from application settings, I can't see how you get that in your CreateToken() method, but I assume it's from the same settings file. Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM