5

Я реализую приложение Asp.NET MVC с использованием модели аутентификации и авторизации Identity 2.x.Пользовательские претензии, потерянные при повторной проверке подлинности

Во время процесса входа в систему я добавляю пользовательские претензии (не сохраняются в БД!), Получая данные, переданные в Login from, в 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 })); 

     } 

    } 

Процесс проверки определяется в OnValidationIdentity который я havn't сделал много, чтобы настроить. Когда validationInterval проходит (... или лучше говорит, что половина пути к validationInterval) Идентификация получает re generatd и пользовательские претензии теряются.

 // 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", 
     }); 

Я думаю, что если какое-то, как быть в состоянии передать текущие Претензии к 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; 
    } 

Любая помощь приветствуется.

Благодаря

+0

Давай? Никто? –

ответ

7

проблема решена (это seemms), я отправляю мое решение, так как я havn't нашел может присваивать ответы, и я думаю, что это может быть полезным для других.

Право трек был найден в ответе на вопрос Reuse Claim in regenerateIdentityCallback in Owin Identity in MVC5

Я просто был немного изменить код, так как 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", 
     }); 

ПРИМЕЧАНИЕ: Пожалуйста, обратите внимание, что в моем образце ExpireTimeSpan и validateInterval смехотворно короткий, так как Цель здесь заключалась в том, чтобы вызывать наиболее частое подтверждение для целей тестирования.

В 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; 
    } 

Это работает. Не совсем уверен, что это лучшее решение, но если у кого-то есть лучшие подходы, не стесняйтесь улучшать свой ответ.

Спасибо.

Lorenzo

ADDENDUM

Через некоторое время его использования я узнал, что реализовано в GenerateUserIdentityAsync (...) может создать проблемы при использовании в сочетании с @ Html.AntiForgeryToken ().Моя предыдущая реализация продолжила бы добавлять уже существующие претензии при каждой повторной аттестации. Это смущает логику AntiForgery, которая вызывает ошибку. Чтобы предотвратить это, я вновь implemnted это так:

/// <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; 
    } 

} 

ДОБАВЛЕНИЕ 2

я должен был уточнить мне механизм, потому что мой previosu ADDENDUM бы привести в некоторых специфических случаях к той же проблеме, описанной в ходе повторного -Проверка. Ключом к текущему окончательным решением является добавление претензий, которые я могу четко идентифицировать и добавлять только те, которые находятся во время повторной проверки, без необходимости пытаться различать betweeb native (ASP Identity) и мои. Так что теперь во время LogIn добавить следующие пользовательские претензий: «CustomClaim»

User.Claims.Add(new ApplicationIdentityUserClaim() { ClaimType = "CustomClaim.CultureUI", ClaimValue = UserProfile.CultureUI }); 
User.Claims.Add(new ApplicationIdentityUserClaim() { ClaimType = "CustomClaim.CompanyId", ClaimValue = model.CompanyId }); 

Обратите внимание на тип претензии, который теперь начинается с.

Затем в повторной проверке я сделать следующее:

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; 
    } 

UserIdentity не содержит пользовательские претензий, в то время как CurrentIdentity действительно содержит оба, но только один я должен «повторно прикрепить» к текущей идентичности являются моими обычными.

Пока это работает нормально, поэтому я буду отмечать это как ответ.

Надеюсь, это поможет!

Lorenzo