【问题标题】:JWT authentication always return 401 HTTP Error asp.net coreJWT 身份验证始终返回 401 HTTP 错误 asp.net core
【发布时间】:2021-10-14 15:16:01
【问题描述】:

我每次尝试登录时都会收到相同的错误,即 401 Http 错误。我正在使用 JWT 进行身份验证。

下面是我的启动课:

public class Startup
{
    private readonly IConfiguration _configuration;
    public Startup(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews().AddRazorRuntimeCompilation();
        services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(_configuration.GetConnectionString("DBCS")));
        services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<DatabaseContext>().AddDefaultTokenProviders();

        services.AddSingleton<EmailHelper>();
        services.AddScoped<IUnitOfWork, UnitOfWork>();
        services.AddTransient<IProductService, ProductService>();
        services.AddTransient<ICustomerService, CustomerService>();
        services.AddTransient<ISelectListService, SelectListService>();
        services.AddTransient<ITokenService, TokenService>();
        services.AddTransient<UserResolverService>();
        services.AddAutoMapper(typeof(Startup));
        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromMinutes(180);
        });

        var secretKey = Encoding.ASCII.GetBytes(_configuration["JWT:key"]);
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(jwt =>
        {
            var key = Encoding.ASCII.GetBytes(_configuration["JWT:key"]);
            jwt.SaveToken = true;
            jwt.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                RequireExpirationTime = false,
                ValidateLifetime = true
            };
        });

        //Localization
        services.AddLocalization(options => options.ResourcesPath = "Resources");

        services.AddMvc()
             .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
             .AddDataAnnotationsLocalization(options =>
             {
                 options.DataAnnotationLocalizerProvider = (type, factory) =>
                     factory.Create(typeof(SharedResource));
             });

        services.AddMvc()
           .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
           .AddDataAnnotationsLocalization(options =>
           {
               options.DataAnnotationLocalizerProvider = (type, factory) =>
                   factory.Create(typeof(SharedResource));
           });

    services.Configure<RequestLocalizationOptions>(options =>
    {
        var culture_en = CultureInfo.CreateSpecificCulture("en-US");
        //var culture_ar = CultureInfo.CreateSpecificCulture("ar-JO");
        var supportedCultures = new[]
        {
            culture_en,
            //culture_ar,
        };

        options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
        options.SupportedCultures = supportedCultures;
        options.SupportedUICultures = supportedCultures;
        options.RequestCultureProviders = new[]{ new RouteDataRequestCultureProvider{
                IndexOfCulture=1,
                IndexofUICulture=1
            }};
        });
        services.Configure<RouteOptions>(options =>
        {
            options.ConstraintMap.Add("culture", typeof(LanguageRouteConstraint));
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            //app.UseExceptionHandler("/Error");
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseStaticFiles();
        //app.UseStatusCodePagesWithRedirects("/Error");
        app.UseHttpsRedirection();
        app.UseSession();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "LocalizedAreas",
                pattern: "{culture=en}/{area:exists}/{controller=Home}/{action=Index}/{id?}"
            );

            endpoints.MapControllerRoute(
                name: "Areas",
                pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
            );

            endpoints.MapControllerRoute(
                name: "LocalizedDefault",
                pattern: "{culture=en}/{controller=Home}/{action=Index}/{id?}"
            );

            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{*catchall}",
                defaults: new { controller = "Home", action = "RedirectToDefaultLanguage", culture = "en" });
        });
    }

    public class LanguageRouteConstraint : IRouteConstraint
    {
        public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (!values.ContainsKey("culture"))
                return false;

            var culture = values["culture"].ToString();
            return culture == "en" || culture == "ar";
        }
    }
}

下面是我的名为 Account 的控制器,它确保用户存在并相应地生成一个令牌:

[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginVM model)
{
    var user = await _userManager.FindByNameAsync(model.Email);
    if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
    {
        var authClaim = new List<Claim> {
            new Claim("Id", user.CustomerId.ToString()),
            new Claim(JwtRegisteredClaimNames.Email, user.Email),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };
        var JWTtoken = new JwtSecurityToken(
            issuer: _configuration["JWT:issuer"],
            audience: _configuration["JWT:audience"],
            claims: authClaim.AsEnumerable<Claim>(),
            expires: new DateTimeOffset(DateTime.Now.AddMinutes(90)).DateTime,
                    signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration["JWT:key"])), SecurityAlgorithms.HmacSha256)
        );
        var token = new JwtSecurityTokenHandler().WriteToken(JWTtoken);
        if (token != null)
        {
            return RedirectToAction("Index", "Profile", new { area = "Store" });
        }
        else
        {
            ModelState.AddModelError("", (string)_localizer["InvalidLogin"]);
            return View(model);
        }
    }
    ModelState.AddModelError("", (string)_localizer["InvalidLogin"]);
    return View(model);
}

生成令牌后,我将用户重定向到他/她的个人资料,下面是个人资料控制器:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Area("Store")]
public class ProfileController : Controller
{
    [HttpGet]
    public IActionResult Index()
    {
        return View();
    }
}

提前感谢您,非常感谢您的帮助。

【问题讨论】:

  • 您的代码没有显示客户端如何检索令牌或服务器如何验证令牌。
  • Login 不会将令牌返回给调用者。您是否正在调试代码,手动复制token,并将其分配到某个地方进行测试?
  • 正如 Tom W 所说,当您调用另一个授权请求时,您需要将啤酒令牌复制到标头(或任何其他方式)。否则总是返回 401。另外,ValidateIssuerValidateAudience 设置为 false,所以JWTtoken 不需要添加受众和发布者。
  • 另外,如果你使用mvc,我认为cookie认证是一种更好的方式。 Jwt 令牌认证更适合 web api 项目。

标签: c# asp.net-core jwt


【解决方案1】:

谢谢大家的cmets和帮助,我上网找到了解决问题的办法。我通过在 Startup 类 Configure 方法中添加以下内容来解决它:

app.UseSession();
            app.Use(async (context, next) =>
            {
                var token = context.Session.GetString("token");
                if (!string.IsNullOrEmpty(token))
                {
                    context.Request.Headers.Add("Authorization", "Bearer " + token);
                }
                await next();
            });
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints()

【讨论】:

    猜你喜欢
    • 2019-04-19
    • 1970-01-01
    • 2019-09-13
    • 2021-08-22
    • 1970-01-01
    • 2021-05-20
    • 2019-09-06
    • 2021-04-20
    • 2018-08-07
    相关资源
    最近更新 更多