Claims Identity MVC

4

I'm having a hard time implementing Claims to perform user authorizations in my project, I've read a lot but can not execute. I'm using the NHibernate.AspNet.Identity for this reason I can not run as in forums and tutorials read, but I'm not sure.

Example of how I tried to create:

public async Task Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            ApplicationUser signedUser = _userManager.FindByEmail(model.Email);
            var result = await _signInManager.PasswordSignInAsync(signedUser.UserName, model.Password, model.RememberMe, shouldLockout: false);

            var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.Email), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);
            identity.AddClaim(new Claim(ClaimTypes.Role, "Adm"));
            identity.AddClaim(new Claim(ClaimTypes.GivenName, "Teste"));
            identity.AddClaim(new Claim(ClaimTypes.Sid, signedUser.userID));

            switch (result)
            {
                case SignInStatus.Success:
                    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("", "Login ou Senha incorretos.");
                    return View(model);
            }

        }

Example of how I'm trying to verify:

  • I created a table to save Claims and UserClaims, now I would like to know how to log in and load these claims without having to go to the bank?
  • How to validate claims in my Methods?
  • Is there any more effective way to authenticate users without using Claims or Roles?
  • Thank you for your attention!

        
    asked by anonymous 06.07.2017 / 05:08

    2 answers

    5

    Claims need to be added before doing the SignIn of the user, and should be added to the ClaimsIdentity object that is created to effect that SignIn .

    >

    You must have a class that inherits from IdentityUser and is used with identity classes, probably something like ApplicationUser , containing the following method:

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
    
        // aqui você adiciona tuas claims
        userIdentity.AddClaim(new Claim(ClaimTypes.Role, "Adm"));
        userIdentity.AddClaim(new Claim(ClaimTypes.GivenName, "Teste"));
        userIdentity.AddClaim(new Claim(ClaimTypes.Sid, this.userID));
    
        return userIdentity;
    }
    

    This is the ideal place for you to add your claims.

    Explanation

    I honestly find these tutorials out there complicated and incomplete, I will try to detail without complicating so much (I hope so). Identity works with a number of classes, such as:

  • SignInManager
  • UserManager
  • UserStore
  • IdentityUser
  • IdentityRole
  • etc ...
  • If you have not changed much of the default template, there in the App_Start folder you should have a IdentityConfig.cs file where you will find a ApplicationSignInManager class (inheriting from SignInManager<ApplicationUser, string> ). This is the class that is used to perform the SignIn of users, and has different forms of login: PasswordSignInAsync() (which is the one you use in your example), SignInAsync() , ExternalSignInAsync() ,% with%.

    Anyway, all of them will at some point need to create the user's identity, which is an object of type TwoFactorSignInAsync() . For this, during the SignIn process (regardless of which method has been used), the ClaimsIdentity method of this class will be called. You should note that this CreateUserIdentityAsync class overrides this method with the following implementation:

    public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
    {
        return user.GenerateUserIdentityAsync((UserManager)UserManager);
    }
    

    That is, it calls this method ApplicationSignInManager of your user, which is some class that inherits from GenerateUserIdentityAsync . This method must create and return an object of type IdentityUser that will be used in the process of SignIn .

    So this method is the ideal place for creating your customized claims, as I see it. In addition, you should note that in the ClaimsIdentity file in that same folder, it has the following code:

    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<UserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        }
    });
    

    Basically, this setting causes identity to every "x" minute (in this case 30) to revalidate its user identity by executing the method contained in the lambda expression, in which case the same Startup.Auth.cs of your user. By creating your claims within this method, you guarantee that they will remain even after that period in which the identity revalidates the user.

        
    07.07.2017 / 03:10
    2

    Responding in parts.

    1 - At some point you will have to search the Claims database to add it to the context of the logged in user. Partially you are doing this, there are some things that I will demonstrate:

    In this session you are searching the user, validating username and password and creating some Claims.

        ApplicationUser signedUser = _userManager.FindByEmail(model.Email);
        var result = await _signInManager.PasswordSignInAsync(signedUser.UserName, model.Password, model.RememberMe, shouldLockout: false);
    
        var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.Email), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);
        identity.AddClaim(new Claim(ClaimTypes.Role, "Adm"));
        identity.AddClaim(new Claim(ClaimTypes.GivenName, "Teste"));
        identity.AddClaim(new Claim(ClaimTypes.Sid, signedUser.userID));
    

    All right here, but you need to add the Claims to the user context by doing this:

        public IAuthenticationManager AuthenticationManager
        {
            get { return HttpContext.Current.GetOwinContext.Authentication; } 
        }
    
        public async Task Login(LoginViewModel model, string returnUrl) {
             //... seu código de busca e validação de usuário
    
             ApplicationUser signedUser = _userManager.FindByEmail(model.Email);
             var result = await _signInManager.PasswordSignInAsync(signedUser.UserName, model.Password, model.RememberMe, shouldLockout: false);
    
             var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.Email), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);
             identity.AddClaim(new Claim(ClaimTypes.Role, "Adm"));
             identity.AddClaim(new Claim(ClaimTypes.GivenName, "Teste"));
             identity.AddClaim(new Claim(ClaimTypes.Sid, signedUser.userID));
    
             AuthenticationManager.SignIn(New AuthenticationProperties {
                AllowRefresh = true,
                IsPersistent = true,
                ExpiresUtc = DateTime.UtcNow.AddDays(1)
             });
        }
    

    To search for the existing value in a Claim, use:

        public string BuscaValorClaim(string strNomeClaim) {
         ClaimsPrincipal listaClaim = ((ClaimsPrincipal), Threading.Thread.CurrentPrincipal)
         return listaClaim.FindFirst((x) => x.Type == strNomeClaim).Value.ToString()
        }
    
        
    06.07.2017 / 13:57