2015-06-19 134 views
9

我需要在用户登录成功后向用户的身份添加索赔。这是我认为它需要发生:成功登录后添加索赔

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl, string myClaimValue) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false); 
    switch (result) 
    { 
     case SignInStatus.Success: 
     UserManager.AddClaim(User.Identity.GetUserId(), new Claim("MyClaim", myClaimValue)); 
     return RedirectToLocal(returnUrl); 
     case SignInStatus.LockedOut: 
     return View("Lockout"); 
     case SignInStatus.RequiresVerification: 
     return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); 
     case SignInStatus.Failure: 
     default: 
     ModelState.AddModelError("", "Invalid login attempt."); 
     return View(model); 
    } 
} 

我认为这是正确的做法,但在调用User.Identity.GetUserId()抛出异常。它看起来像User.Identity未成功登录更新。为了取代这种现实,我最好的办法是获取新登录用户的ID,以便我可以添加索赔?

还是我这样做全错了?

+0

@约翰·桑德斯谢谢!非常有意义。 – itslittlejohn

+0

我越想这件事,就越觉得我做错了。在我看来,索赔是识别用户的东西。我的目标是存储一些在登录时在客户端计算的用户的真实数据。此数据不应存储在数据库中,但应在登录时与登录用户关联。 – itslittlejohn

+0

索赔不仅仅是识别用户。它们是用户断言是真实的一组“命题”。例如,“我处于以下角色集合”是一个合理的主张。 –

回答

2

这将存储要求数据库UserManager.AddClaim(User.Identity.GetUserId(), new Claim("MyClaim", myClaimValue));

如果你只是想与登录用户相关的权利,当他登录时,你必须覆盖SignInManager

public override async Task SignInAsync(ApplicationUser user, bool isPersistent, bool rememberBrowser) { var userIdentity = await CreateUserIdentityAsync(user); // your code here userIdentity.AddClaim(new Claim(ClaimTypes.Gender, "male")); // AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.TwoFactorCookie); if (rememberBrowser) { var rememberBrowserIdentpublic override async Task SignInAsync(ApplicationUser user, bool isPersistent, bool rememberBrowser) 
{ 
    var userIdentity = await CreateUserIdentityAsync(user); 

    // your code here 
    userIdentity.AddClaim(new Claim(ClaimTypes.Gender, "male")); 
    // 

    uthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.TwoFactorCookie); 
    if (rememberBrowser) 
    { 
     var rememberBrowserIdentity = AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(ConvertIdToString(user.Id)); 
     AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, userIdentity, rememberBrowserIdentity); 
    } 
    else 
    { 
     AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, userIdentity); 
    } 
} 
+0

我明白了,谢谢。问题是,当我尝试访问其他控制器中的声明时,它不存在。此外,当我如上所述创建新的'ClaimIdentity'时,'User.Identity.IsAuthenticated'为false。我不确定问题在于User.Identity似乎没有完全初始化,或者我创建后没有对这个新身份做任何事情。 – itslittlejohn

+0

@itslittlejohn这不工作,如你所说,更新答案。 – tmg

+0

感谢您的更新。我会尽快对此进行测试。 – itslittlejohn

4

附加的权利要求的SignInAsync方法必须在SignInManager.PasswordSignInAsync被触发前设置。这可以通过自定义ClaimsIdentityFactory来完成:

public class ApplicationClaimsIdentityFactory : ClaimsIdentityFactory<ApplicationUser> 
{ 
    // This claim value is taken from Login View 
    public static readonly string MyClaimKey = "app:MyClaimKey"; 
    public string MyClaimValue { get; set; } 

    public async override Task<ClaimsIdentity> CreateAsync(UserManager<ApplicationUser, string> manager, ApplicationUser user, string authenticationType) 
    { 
     var identity = await base.CreateAsync(manager, user, authenticationType); 
     identity.AddClaim(new Claim(MyClaimKey, MyClaimValue)); 
     return identity; 
    } 
} 

步骤号前申请这家工厂:

UserManager.ClaimsIdentityFactory = new ApplicationClaimsIdentityFactory() 
     { 
      MyClaimValue = loginModel.MyClaimValue 
     }; 
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);