ASP.NET 核心 JWT 身份验证总是抛出 401 未经授权

Vis*_*osh 13 asp.net asp.net-authorization jwt asp.net-web-api asp.net-core

我正在尝试尽可能简单地在我的 asp.net 核心 webAPI 上实现 JWT 身份验证。我不知道我错过了什么,但即使使用正确的不记名令牌,它也总是返回 401 。

这是我的 configureServices 代码

public void ConfigureServices(IServiceCollection services)
        {
            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(Encoding.ASCII.GetBytes("A_VERY_SECRET_SECURITY_KEY_FOR_JWT_AUTH")),
                       ValidateAudience = false,
                       ValidateIssuer = false,
                   };
               }
                );
            services.AddControllers();

            services.AddDbContext<dingdogdbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("dingdogdbContext")));
        }

Run Code Online (Sandbox Code Playgroud)

这就是我生成令牌的方式

        [AllowAnonymous]
        [HttpPost("/Login")]
        public ActionResult<User> Login(AuthModel auth)
        {
            var user = new User();
            user.Email = auth.Email;
            user.Password = auth.Password;
            //var user = await _context.User.SingleOrDefaultAsync(u=> u.Email == auth.Email && u.Password==auth.Password);
            //if(user==null) return NotFound("User not found with this creds");

            //starting token generation...
            var tokenHandler = new JwtSecurityTokenHandler();
            var seckey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("A_VERY_SECRET_SECURITY_KEY_FOR_JWT_AUTH"));
            var signingCreds = new SigningCredentials(seckey, SecurityAlgorithms.HmacSha256Signature);
            var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
            {
                Subject = new System.Security.Claims.ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, user.Id.ToString()) }),
                SigningCredentials = signingCreds,
                Expires = DateTime.UtcNow.AddDays(7),
            });
            user.Token = tokenHandler.WriteToken(token);
            return user;
        }
Run Code Online (Sandbox Code Playgroud)

我在 app.useRouting() 之后添加了 app.useAuthorization()。当我向 /Login 发送 POST 请求时,我得到了令牌。但是当我使用令牌查询任何其他使用邮递员的端点(在邮递员的授权/JWT 中添加令牌)时,每次都会得到 401 未经授权。我还缺少什么吗?

Jak*_*era 35

请记住,在UseAuthenticationUseRoutingUseAuthorization中间件必须正确为了使ASP框架适当注入身份上下文的HTTP请求。

它应该是这样的:(.NET Core 3.1)

编辑:相同的代码适用于 .NET 5

            app.UseAuthentication();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
Run Code Online (Sandbox Code Playgroud)

  • 不确定为什么 .Net Core 文档另有建议?https://learn.microsoft.com/en-us/aspnet/core/security/authentication/?view=aspnetcore-5.0 它明确表示在 UseRouting 之后和 UseEndpoints 之前 (2认同)

Hoq*_*dul 17

步骤1:首先确定stratup.cs类中configure方法的顺序

下面我给出了 asp.net core 3.1 的有效订单

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

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

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
Run Code Online (Sandbox Code Playgroud)

如果第一步不起作用,请尝试第 2 步:确保令牌验证参数和令牌生成参数和算法相同,请转到 startup.cs 类的 ConfigureServices 方法,并转到您生成的类或方法在我的情况下,令牌是 UserService 类

ConfigureServices 方法代码:

public void ConfigureServices(IServiceCollection services)
    {
        var connectionString = Configuration.GetConnectionString("mySQLConnectionString");

        services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(connectionString));
        services.AddIdentity<IdentityUser, IdentityRole>(options =>
        {
            options.Password.RequireDigit = true;
            options.Password.RequireLowercase = true;
            options.Password.RequiredLength = 5;
        }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

        services.AddAuthentication(auth =>
        {
            auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidAudience = Configuration["AuthSettings:Audience"],
                ValidIssuer = Configuration["AuthSettings:Issuer"],
                RequireExpirationTime = true,
                IssuerSigningKey =
                    new SymmetricSecurityKey(
                        Encoding.UTF8.GetBytes(Configuration["AuthSettings:key"])),
                ValidateIssuerSigningKey = true,

            };
        });
        services.AddScoped<IUserService, UserService>();
        services.AddControllers();
    }
Run Code Online (Sandbox Code Playgroud)

代币生成代码:

 public async Task<UserManagerResponse> LoginUserAsync(LoginVIewModel model)
    {
        var user = await _userManager.FindByEmailAsync(model.Email);
        if(user == null)
        {
            return new UserManagerResponse
            {
                Message = "There is no user with that email",
                iSSuccess= false
            };
        }
        var result = await _userManager.CheckPasswordAsync(user, model.Password);
        if(! result)
        {
            return new UserManagerResponse
            {
                Message = "Your Provided password not match eith our system ",
                iSSuccess = false
            };

        }

        var clims = new[]
        {
            new Claim("Email", model.Email),
            new Claim(ClaimTypes.NameIdentifier, user.Id)
        };
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["AuthSettings:key"]));
        var token = new JwtSecurityToken(
            issuer: _configuration["AuthSettings:Issuer"],
            audience: _configuration["AuthSettings:Audience"],
            claims: clims,
            expires: DateTime.Now.AddDays(30),
            signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
            );
        string tokenAsString = new JwtSecurityTokenHandler().WriteToken(token);

        return new UserManagerResponse
        {
            Message = tokenAsString,
            iSSuccess = true,
            ExpireDate = token.ValidTo
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

还请注意,就我而言,我在 appsetting.json 中有一些拼写错误例如,在令牌生成代码中,我将其称为 Audince,但在 appSetting.json 中它是 Audience。这就是为什么两个 Audience 不匹配的原因。

             audience: _configuration["AuthSettings:Audince"]
Run Code Online (Sandbox Code Playgroud)

Appsetting.json 代码:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

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

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

在解决这个问题几个小时后,并尝试了多个问题中的不同内容。以下是我识别问题的方法:

打开文件Microsoft.AspNetCore.Authentication中包的日志记录appsettings.json

{
  "Logging": {
    "Console": {
      "LogLevel": {
        "Microsoft.Hosting.Lifetime": "Trace",
        "Microsoft.AspNetCore.Authentication": "Information"
      }
    }
  },
// other attributes
}
Run Code Online (Sandbox Code Playgroud)

这会将身份验证失败记录到 Visual Studio 服务器控制台。

在此输入图像描述

new JwtSecurityToken就我而言,我在生成令牌时没有将 expires 参数传递给构造函数。但我正在验证构造函数中的令牌生命周期TokenValidationParameters


Alo*_*mar 2

首先,您需要检查使用configureServices代码生成的JWT令牌是否有效。要验证JWT令牌,您可以使用JWT调试器。它将 JWT 令牌值解析为每个参数,您可以通过该参数验证哪些参数值分配不正确,并且 JWT 调试器还会为您提供 JWT 有效或无效。一旦弄清楚这一点,您就可以解决已识别的错误或采取下一步行动。