我正在使用带有ClaimsIdentity
的ASP.NET身份验证用户身份。验证用户身份后,属性User.Identity
包含一个ClaimsIdentity
实例。
但是,在登录请求期间不是这种情况:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, false, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
var identity = User.Identity;
------------> // identity is of type WindowsIdentity <------------
return RedirectToLocal(returnUrl);
如您所见,即使登录成功,属性
User.Identity
仍未设置为ClaimsIdentity
实例。我认为这是合理的,这意味着SignInManager
不会更新属性,因此我们必须等到下一个请求才能看到登录结果。但是,我必须在方法
PasswordSignInAsync
之后执行其他逻辑,因此我需要一种方法来在switch语句的.Success分支中获取ClaimsIdentity
实例。在调试器中检查
SignInManager
时,我看到它的类型是Microsoft.Owin.Security.AuthenticationManager
,它的属性SignInEntry.Item1
包含要查找的ClaimsIdentity
。但是,类型
Microsoft.Owin.Security.AuthenticationManager
不是公共的,因此唯一的方法似乎是使用反射的hack。有没有更好的办法?
最佳答案
我同意,PasswordSignInAsync不将用户实例作为out参数返回是很糟糕的。如果您查看源代码,则可以看到它使用this.UserManager.FindByNameAsync(userName)
通过userName查找用户,然后使用this.UserManager.CheckPasswordAsync(user, password)
验证密码,但是该用户存储在本地变量中。
我认为这应该作为对SignInManager类的改进而提出。
一种可能的(且效率低下的)解决方法是再次查询用户,然后以与SignInManager.SignInAsync相同的方式自己创建声明标识。
ApplicationUser user = await UserManager.FindByNameAsync(model.Email);
ClaimsIdentity claimsIdentity = await SignInManager.CreateUserIdentityAsync(user);