Monday, February 15, 2016

Dynamic Claims in ASP.NET Core

As you know ASP.NET provides claim based authorization using ASP.NET identity system. The claims supported by the identity system should be defined and persisted into the IdentityUserClaim or IdentityRoleClaim table.

I have a requirement where I don’t want my claims to be persisted in the database. I want these claims to be in memory (cookie, token etc) and passed from page to page. For this I need to add these dynamic claims to the Claims Principal identity so that they can be saved to cookie or token. But adding the claims to the current identity is not adding the claims to the current claims of the logged in user.

The trick to set these claims is to set them immediately after user is created. For this I overrode the SignInManager and set the claims in the CreateUserPrincipalAsync. Here is the my code:

    public class ApplicationSignInManager : SignInManager<ApplicationUser>
    {
        private AccountRepository accountRepository;

        public ApplicationSignInManager(AccountRepository accountRepository, UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor, ILogger<SignInManager<ApplicationUser>> logger)
            :base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger)
        {
            this.accountRepository = accountRepository;
        }

        public override async Task<ClaimsPrincipal> CreateUserPrincipalAsync(ApplicationUser user)
        {
            var principal = await base.CreateUserPrincipalAsync(user);
            ClaimsIdentity identity = (ClaimsIdentity)principal.Identity;
            var profile = await Profile.Get(user.UserName, accountRepository);

            //var profile = Profile.Current;
            string companies = String.Join(",", profile.Companies.Select(s => s.CompanyId.ToString()));
            string adminRoles = String.Join(",", profile.AdminRoles);

            //adding custom claim
            identity.AddClaim(new Claim(NTClaimTypes.FirstName, profile.FirstName));
            identity.AddClaim(new Claim(NTClaimTypes.LastName, profile.LastName));
            identity.AddClaim(new Claim(NTClaimTypes.CompanyId, profile.CompanyId.ToString()));
            identity.AddClaim(new Claim(NTClaimTypes.Companies, companies));

            return principal;
        }

    }

In the above code, accountRepository is my database context using which I am fetching the current user details and adding them to the Claims.