l.r*_*ndi 5 validation identity claims-based-identity asp.net-mvc-5
我正在使用Identity 2.x身份验证和授权模型实现Asp.NET MVC应用程序.
在LogIn过程中,我添加自定义声明(不会保留在数据库中!),从LogIn中传递的数据派生到Identity,我可以在以后正确访问它们,直到身份重新生成.
[HttpPost]
[AllowAnonymous]
[ValidateHeaderAntiForgeryToken]
[ActionName("LogIn")]
public async Task<JsonResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
return Json(GenericResponseViewModel.Failure(ModelState.GetErrors("Inavlid model", true)));
using (var AppLayer = new ApplicationLayer(new ApplicationDbContext(), System.Web.HttpContext.Current))
{
GenericResponseViewModel LogInResult = AppLayer.Users.ValidateLogInCredential(ref model);
if (!LogInResult.Status)
{
WebApiApplication.ApplicationLogger.ExtWarn((int)Event.ACC_LOGIN_FAILURE, string.Join(", ", LogInResult.Msg));
return Json(LogInResult);
}
ApplicationUser User = (ApplicationUser)LogInResult.ObjResult;
// In case of positive login I reset the failed login attempts count
if (UserManager.SupportsUserLockout && UserManager.GetAccessFailedCount(User.Id) > 0)
UserManager.ResetAccessFailedCount(User.Id);
//// Add profile claims for LogIn
User.Claims.Add(new ApplicationIdentityUserClaim() { ClaimType = "Culture", ClaimValue = model.Culture });
User.Claims.Add(new ApplicationIdentityUserClaim() { ClaimType = "CompanyId", ClaimValue = model.CompanyId });
ClaimsIdentity Identity = await User.GenerateUserIdentityAsync(UserManager, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, Identity);
WebApiApplication.ApplicationLogger.ExtInfo((int)Event.ACC_LOGIN_SUCCESS, "LogIn success", new { UserName = User.UserName, CompanyId = model.CompanyId, Culture = model.Culture });
return Json(GenericResponseViewModel.SuccessObj(new { ReturnUrl = returnUrl }));
}
}
Run Code Online (Sandbox Code Playgroud)
验证过程在OnValidationIdentity中定义,我没有做太多定制.当validationInterval经过(...或更好地表示在一半到validationInterval)时,身份会重新生成并且自定义声明会丢失.
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(1d),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ApplicationCookie))
},
/// TODO: Expire Time must be reduced in production do 2h
ExpireTimeSpan = TimeSpan.FromDays(100d),
SlidingExpiration = true,
CookieName = "RMC.AspNet",
});
Run Code Online (Sandbox Code Playgroud)
我想我应该如何能够将当前的声明传递给GenerateUserIdentityAsync,以便我可以重新添加自定义Clims,但我不知道如何.
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
// ????????????????????????????
return userIdentity;
}
Run Code Online (Sandbox Code Playgroud)
任何帮助表示赞赏.
谢谢
问题解决了(似乎),我发布我的解决方案,因为我找不到可能适当的答案,我认为它可能对其他人有用.
在MVC5中Owin身份的regenerateIdentityCallback中的重用声明问题的答案中找到了正确的轨道
我刚刚修改了一些代码,因为在我的情况下UserId是字符串类型而不是Guid.
这是我的代码:
在Startup.Auth.cs中
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
//OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
// validateInterval: TimeSpan.FromMinutes(1d),
// regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ApplicationCookie))
OnValidateIdentity = context => SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, string>(
validateInterval: TimeSpan.FromMinutes(1d),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager, context.Identity),
getUserIdCallback: (ci) => ci.GetUserId()).Invoke(context)
},
/// TODO: Expire Time must be reduced in production do 2h
//ExpireTimeSpan = TimeSpan.FromDays(100d),
ExpireTimeSpan = TimeSpan.FromMinutes(2d),
SlidingExpiration = true,
CookieName = "RMC.AspNet",
});
Run Code Online (Sandbox Code Playgroud)
注意:请注意,在我的示例中,ExpireTimeSpan和validateInterval非常简短,因为此处的目的是为了测试目的而导致最多的frequest重新验证.
在IdentityModels.cs中,GenerateUserIdentityAsync的重载将负责将所有自定义声明重新附加到Identity.
/// Generates user Identity based on Claims already defined for user.
/// Used fro Identity re validation !!!
/// </summary>
/// <param name="manager"></param>
/// <param name="CurrentIdentity"></param>
/// <returns></returns>
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager, ClaimsIdentity CurrentIdentity)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Re validate existing Claims here
userIdentity.AddClaims(CurrentIdentity.Claims);
return userIdentity;
}
Run Code Online (Sandbox Code Playgroud)
有用.不确定它是否是最佳解决方案,但如果有人有更好的方法,请随时改进我的答案.
谢谢.
洛伦佐
附录
使用它一段时间后,我发现如果与@ Html.AntiForgeryToken()一起使用,GenerateUserIdentityAsync(...)中实现的内容可能会产生问题.我之前的实现将在每次重新验证时继续添加现有的声明.这会混淆引发错误的AntiForgery逻辑.为了防止我以这种方式重新实现它:
/// <summary>
/// Generates user Identity based on Claims already defined for user.
/// Used fro Identity re validation !!!
/// </summary>
/// <param name="manager"></param>
/// <param name="CurrentIdentity"></param>
/// <returns></returns>
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager, ClaimsIdentity CurrentIdentity)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Re validate existing Claims here
foreach (var Claim in CurrentIdentity.Claims) {
if (!userIdentity.HasClaim(Claim.Type, Claim.Value))
userIdentity.AddClaim(new Claim(Claim.Type, Claim.Value));
}
return userIdentity;
}
}
Run Code Online (Sandbox Code Playgroud)
附录2
我不得不进一步完善我的机制,因为我的previosu ADDENDUM会在一些特殊情况下导致重新验证期间描述的相同问题.当前最终解决方案的关键是添加我可以清楚识别的声明,并在重新验证期间仅添加那些声明,而不必尝试区分本地的(ASP身份)和我的.所以现在在LogIn中我添加以下自定义声明:
User.Claims.Add(new ApplicationIdentityUserClaim() { ClaimType = "CustomClaim.CultureUI", ClaimValue = UserProfile.CultureUI });
User.Claims.Add(new ApplicationIdentityUserClaim() { ClaimType = "CustomClaim.CompanyId", ClaimValue = model.CompanyId });
Run Code Online (Sandbox Code Playgroud)
请注意声明类型,现在以"CustomClaim."开头.
然后在重新验证中,我执行以下操作:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager, ClaimsIdentity CurrentIdentity)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Re validate existing Claims here
foreach (var Claim in CurrentIdentity.FindAll(i => i.Type.StartsWith("CustomClaim.")))
{
userIdentity.AddClaim(new Claim(Claim.Type, Claim.Value));
// TODO devo testare perché va in loop la pagina Err500 per cui provoco volontariamente la duplicazioen delle Claims
//userIdentity.AddClaims(CurrentIdentity.Claims);
}
return userIdentity;
}
Run Code Online (Sandbox Code Playgroud)
userIdentity不包含自定义声明,而CurrentIdentity确实包含两者,但我必须"重新附加"到当前标识的唯一一个是我的自定义声明.
到目前为止它工作正常,所以我将此标记为答案.
希望能帮助到你 !
洛伦佐
| 归档时间: |
|
| 查看次数: |
1534 次 |
| 最近记录: |