【发布时间】: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。另外,
ValidateIssuer和ValidateAudience设置为 false,所以JWTtoken不需要添加受众和发布者。 -
另外,如果你使用mvc,我认为cookie认证是一种更好的方式。 Jwt 令牌认证更适合 web api 项目。
标签: c# asp.net-core jwt