我正在尝试使用 ASP.NET 核心身份 2.0 在现有应用程序中设置身份验证。由于我使用自己的数据库架构和类,因此我有自己的用户类,我必须创建自定义用户商店和自定义用户管理器。
所以我在帐户控制器中有我的登录功能:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Login, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToAction(nameof(Lockout));
}
else
{
ModelState.AddModelError(string.Empty, "Connection failed.");
return View(model);
}
}
return View(model);
}
我有我的自定义用户管理器:
public class CustomUserManager<TUser> : UserManager<TUser> where TUser : User
{
public CustomUserManager(IUserStore<TUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher, IEnumerable<IUserValidator<TUser>> userValidators,
IEnumerable<IPasswordValidator<TUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<TUser>> logger) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
}
public override Task<bool> CheckPasswordAsync(TUser user, string password)
{
bool passwordIsSimilar = password == user.Password;
return new Task<bool>(() => passwordIsSimilar);
}
}
和我的服务声明:
services.AddIdentity<User, ProfileUser>().AddUserManager<CustomUserManager<User>>().AddDefaultTokenProviders();
services.AddTransient<IUserStore<User>, UserIdentity>();
services.AddTransient<IRoleStore<ProfileUser>, ProfileIdentity>();
services.Configure<IdentityOptions>(options =>
{
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
// If the LoginPath isn't set, ASP.NET Core defaults
// the path to /Account/Login.
options.LoginPath = "/Account/Login";
// If the AccessDeniedPath isn't set, ASP.NET Core defaults
// the path to /Account/AccessDenied.
options.AccessDeniedPath = "/Account/AccessDenied";
options.SlidingExpiration = true;
});
我的自定义用户管理器工作,当用户登录时调用CheckPasswordAsync((。但是,在此之后,该函数将等待_signInManager.PasswordSignInAsync(model.登录,模型。密码、型号。记住我,锁定失败:假(;似乎在某个地方阻塞。调试模式下没有错误,执行不会传递到下一行(if (result.成功((
您知道我的代码在执行中阻塞的原因是什么吗?
这里的问题是这一行:
return new Task<bool>(() => passwordIsSimilar);
Task
构造函数实际上并不运行任务;它只是初始化它。调用CheckPasswordAsync
的代码正在等待此任务完成,但由于它永远不会启动,因此不会发生这种情况。
正如Stephen Cleary所写:不要使用Task
或Task<T>
构造函数。相反,在您的示例中,您可以简单地使用Task.FromResult<T>
,如下所示:
return Task.FromResult(passwordIsSimilar);
从本质上讲,这会为您创建一个新的Task
,该已经完成了passwordIsSimilar
的结果。任何解开任务包装的东西(通常使用await
(都将检索passwordIsSimilar
的值。