【问题标题】:ASP.NET core JWT authentication always throwing 401 unauthorizedASP.NET 核心 JWT 身份验证总是抛出 401 未授权
【发布时间】:2020-09-10 14:08:24
【问题描述】:

我正在尝试尽可能简单地在我的 asp.net 核心 webAPI 上实现 JWT 身份验证。 我不知道我错过了什么,但即使使用 proper 不记名令牌,它也总是返回 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")));
        }

这就是我生成令牌的方式

        [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;
        }

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

【问题讨论】:

  • 你是如何传递令牌的?在您的 StartUp.Configure 中,您使用的是 app.UseAuthentication() 吗?
  • 哦,谢谢。我只是在使用 app.UseAuthorization() 而不是 app.UseAuthentication()。添加了它,它起作用了!

标签: asp.net asp.net-core asp.net-web-api jwt asp.net-authorization


【解决方案1】:

请记住,UseAuthenticationUseRoutingUseAuthorization 中间件必须正确,才能使 ASP 框架正确地将身份上下文注入 http 请求。

它应该看起来像这样:(.NET Core 3.1)

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

            app.UseAuthentication();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });

【讨论】:

  • 这应该标记为答案,因为它建议在UseAuthorization()之前添加app.UseAuthentication():如果两个指令的顺序错误,将发出401!
  • 中间件顺序在 .NET Core 3.1 上也为我解决了这个问题。谢谢
  • 完美,这就是解决方案
  • 说真的,你刚刚让我免于酗酒数小时。
  • @DerekWilliams 我不确定它是好是坏:P
【解决方案2】:

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

如果第 1 步不起作用,请尝试第 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();
    }

令牌生成代码:

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

还请注意,在我的情况下,我在 appsetting.json 中有一些拼写错误 例如,在令牌生成代码中,我调用了 Audince,但在 appSetting.json 中它是 Audience。这就是为什么两个受众不匹配的原因。

             audience: _configuration["AuthSettings:Audince"]

Appsetting.json 代码:

"AllowedHosts": "*",
  "AuthSettings": {
    "key": "TThis is mfw sec test token",
    "Audience": "www.mfw.com",
    "Issuer": "www.mfw.com"
  }

【讨论】:

  • 投个赞成票吧。 ?。我浪费了很多天:(
  • 谢谢,Configure里面的顺序很关键:)
【解决方案3】:

这里还有一些其他问题,您可能想看看并可能改进。登录机制当前包含一个有效期为 7 天的令牌。这意味着暴露的令牌仍将允许攻击者在 7 天内访问和冒充用户。一般来说,最好:

  • 让用户登录并生成一个只能使用 1 小时的令牌
  • 给用户一个永久的设备令牌来代表设备
  • 验证设备和令牌(即使已过期)并可能生成新令牌。

这使用户能够“退出”所有会话,以防万一出现问题。具体来说,大多数身份验证提供程序(例如Auth0)或授权提供程序(例如Authress)都可以使用这些功能和更多功能。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2021-09-28
      • 1970-01-01
      • 2021-08-22
      • 2019-06-09
      • 2017-05-13
      • 2021-04-24
      • 2021-07-17
      • 2020-10-29
      • 2021-02-16
      相关资源
      最近更新 更多