ASP.NET核心JWT身份验证始终抛出未经授权的401

时间:2020-05-23 18:42:17

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

我正在尝试尽可能简单地在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未经授权。 我还有什么想念的吗?

4 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分: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类< / p>

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中有一些拼写错误 例如,在令牌生成代码中,我已将代码称为Audience,但在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"
  }

答案 2 :(得分:0)

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

答案 3 :(得分:0)

这里还有其他一些问题,您可能需要研究一下并有可能改善。当前登录机制包含一个有效期为7天的令牌。这意味着暴露的令牌仍将允许攻击者访问并假冒用户7天。通常,最好这样做:

  • 登录用户并生成仅可使用1个小时的令牌
  • 为用户提供永久的设备令牌以代表设备
  • 验证设备和令牌(即使已过期),并可能生成新令牌。

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