5

ID 2.x 인증 및 권한 부여 모델을 사용하여 Asp.NET MVC 응용 프로그램을 구현하고 있습니다.ID 재 인증에 대한 사용자 지정 클레임이 손실되었습니다.

LogIn 프로세스 중에 LogIn에서 전달 된 데이터에서 파생 된 사용자 지정 클레임 (DB에 유지되지 않음)을 추가하고 나중에 ID에 다시 생성 될 때까지 올바르게 액세스 할 수 있습니다.

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

     } 

    } 

검증 과정은 내가 사용자 정의 할 수 많은 일을 havn't는 OnValidationIdentity에 정의되어 있습니다. validationInterval이 (... 또는 그 이상으로) validationInterval의 절반이라고 말하면 ID가 생성되고 사용자 지정 클레임이 손실됩니다.

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

나는 좀 나는 정의 Clims을 다시 추가 할 수 있도록 GenerateUserIdentityAsync 현재 클레임을 통과 할 수있는 방법을 생각하지만, 내가 어떻게가 모른다.

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

도움을 주시면 감사하겠습니다. 내가 대답을 적절한 수 발견 havn't는 이후

+0

어서 오시겠습니까? 아무도? –

답변

7

문제가 해결

덕분에 (이 seemms), 내 솔루션을 게시하고 나는 그것이 다른 사람에게 유용 할 수 있습니다 생각합니다.

오른쪽 트랙 난 그냥 내 경우에는 사용자 아이디가 가이 드 타입 문자열이며,하지 이후 코드를 약간 수정했다 질문 Reuse Claim in regenerateIdentityCallback in Owin Identity in MVC5

에 대한 답변에서 발견되었다.

참고

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

Startup.Auth.cs에서 : 여기

내 코드 내 샘플 ExpireTimeSpan에validateInterval이 때문에 터무니없이 짧은 유의하시기 바랍니다 여기서의 목적은 테스트 목적을 위해 가장 자주 재 검증을하는 것이 었습니다.

In IdentityModels.cs는 모든 사용자 지정 클레임을 Identity에 다시 연결하는 GenerateUserIdentityAsync의 오버로드를 처리합니다.

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

작동합니다. 그것이 최상의 해결책인지는 잘 모르겠지만 누군가가 더 나은 접근법을 가지고 있다면 제 대답을 자유롭게 개선하십시오.

감사합니다.

로렌조

부칙

약간의 시간이 그것을 사용한 후 나는 (@ Html.AntiForgeryToken와 함께 사용하면 문제를 줄 수도 GenerateUserIdentityAsync (...)에 구현하는 것을 발견).이전 구현에서는 각 재확인시 기존의 Claims를 계속 추가합니다. 이로 인해 오류가 발생하는 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; 
    } 

} 

칙 내 previosu의 부칙이 다시시 설명 같은 문제에 대한 몇 가지 독특한 경우에 이어질 것이기 때문에 나에게 더 메커니즘을 수정했습니다 2

: 나는 이런 식으로 implemnted 다시 한 것을 방지하기 위해 -확인. 결정적인 해결책의 열쇠는 내가 명확하게 식별 할 수있는 주장을 추가하고 원래의 것 (ASP Identity)과 광산을 구별하지 않고도 재확인 중에있는 것만 추가하는 것입니다. 는 이제 로그인 할 때 나는 다음과 같은 사용자 지정 클레임 추가합니다 ". 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가 모두 포함 않지만, 사용자 지정 클레임을 포함하지만,하지 않습니다 내가 현재 ID에 "다시 연결"할 수있는 유일한 일 내 습관이야.

지금까지 문제가 없으므로이 답변을 답으로 표시하겠습니다.

희망이 있습니다.

로렌조

관련 문제