C# 成功登录时添加声明
我需要在用户成功登录后添加对用户身份的声明。这就是我认为需要实现的地方:C# 成功登录时添加声明,c#,asp.net-mvc,asp.net-identity,C#,Asp.net Mvc,Asp.net Identity,我需要在用户成功登录后添加对用户身份的声明。这就是我认为需要实现的地方: public async Task<ActionResult> Login(LoginViewModel model, string returnUrl, string myClaimValue) { if (!ModelState.IsValid) { return View(model); } var result = await SignInManager.Passw
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);
}
}
公共异步任务登录(LoginViewModel模型、字符串returnUrl、字符串myClaimValue)
{
如果(!ModelState.IsValid)
{
返回视图(模型);
}
var result=await-SignInManager.PasswordSignInAsync(model.UserName、model.Password、model.RememberMe、shouldllockout:false);
开关(结果)
{
案例标志状态成功:
UserManager.AddClaim(User.Identity.GetUserId(),新声明(“MyClaim”,myClaimValue));
返回重定向到本地(returnUrl);
案例标志状态锁定输出:
返回视图(“锁定”);
案例标志状态。要求验证:
return RedirectToAction(“SendCode”,new{ReturnUrl=ReturnUrl,RememberMe=model.RememberMe});
案例信号状态故障:
违约:
AddModelError(“,”登录尝试无效“);
返回视图(模型);
}
}
我认为这是正确的方法,但是调用User.Identity.GetUserId()
会引发异常。看起来像是用户。成功登录不会更新身份。代替这种现实,对于我来说,获得新登录的用户id以便添加索赔的最佳方式是什么
还是我做错了?这将把声明存储到数据库UserManager.AddClaim(User.Identity.GetUserId(),newclaim(“MyClaim”,myClaimValue))代码>
如果您希望在登录用户登录时将声明与他关联,则必须覆盖SignInManager的SignInAsync
方法
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);
// add your claims here
userIdentity.AddClaim(new Claim(ClaimTypes.Gender, "male"));
//
AuthenticationManager.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);
}
}
必须在触发SignInManager.PasswordSignInAsync之前设置其他声明。这可以通过自定义ClaimSideEntityFactory完成:
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;
}
}
@约翰·桑德斯,谢谢!这很有道理。我越想这件事,就越觉得我做错了。在我看来,声明是识别用户的东西。我的目标是存储一些关于用户的真实数据,这些数据是在登录时在客户机上计算的。此数据不应存储在数据库中,但应在登录用户登录时与该用户关联。声明不仅仅用于标识用户。它们是用户断言为真的一组“命题”。例如,“我在以下角色中”是一个合理的说法。@JohnSaunders感谢您的解释。这是有道理的,我认为我使用它们的方式是合理的。我明白了,谢谢。问题是,当我试图在其他控制器中访问该声明时,它并不存在。此外,当我像上面所做的那样创建一个新的claiminentity
时,User.Identity.IsAuthenticated
为false。我不确定问题是否在于User.Identity
似乎没有完全初始化,或者在创建新标识后,我没有对其进行任何操作。@itslitlejohn这与您所说的不一样,正在更新答案。感谢您的更新。我将尽快对此进行测试。我最终只使用了session变量。这仍然不起作用,因为我的声明值是从登录请求动态传入的。因为这似乎很难处理索赔,我认为这是错误的方法。如果我错了,请纠正我。问题不在于如何在成功登录后添加声明吗?回答“必须在”登录之前设置,而不提供任何支持该语句的内容,对阅读答案的人来说并没有真正的帮助。@MladenB。您在登录之前将索赔工厂设置为signinmanager,以便在发生登录时使用您准备的工厂。你是对的,这与问题有关,但与问题的答案无关。
UserManager.ClaimsIdentityFactory = new ApplicationClaimsIdentityFactory()
{
MyClaimValue = loginModel.MyClaimValue
};
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);