Sunday, April 2, 2017

Storing Identity Claims in Session or Redis


ASP.NET Core Identity by default uses cookies to store claims. If your authorization is very granular then you will end up using many claims. With all these claims stored in cookie, the cookie size gets bigger and you can exceed the cookie limit.

We can achieve the authorization granularity without exceeding the cookie limit and impacting the way ASP.NET Identity authorizes users by storing the claims in session, Redis or any other memory storage.

Below are the steps I implemented to store the claims in session.

First let’s store the claims in session (assuming that the ASP.NET Core Session is already configured). During authentication, Identity system uses SignInManager for creating principal object of the logged in user. While creating the principal object, Identity populates the claims. We can override this SignInManager and store the claims as shown below:

public class ApplicationSignInManager : SignInManager<ApplicationUser>
{
    private IHttpContextAccessor contextAccessor;

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

    public override async Task<ClaimsPrincipal> CreateUserPrincipalAsync(ApplicationUser user)
    {
        var principal = await base.CreateUserPrincipalAsync(user);
        ClaimsIdentity identity = (ClaimsIdentity)principal.Identity;

        // storing claims in session and removing them. These claims will be added by Transformer
        List<ClaimModel> sessionClaims = new List<ClaimModel>();
        List<Claim> identityClaims = identity.Claims.ToList();
        foreach (var claim in identityClaims)
        {
            sessionClaims.Add(new ClaimModel() { ClaimType = claim.Type, ClaimValue = claim.Value });
            identity.RemoveClaim(claim);
        }

        this.contextAccessor.HttpContext.Session.SetString("IdentityClaims", JsonConvert.SerializeObject(sessionClaims));

        return principal;
    }
}

The Identity system should be configured to use our ApplicationSignInManager instead of the default one. For this we need to define the dependency injection in the Startup under ConfigureServices

services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();

As you see with above code claims are removed from the principal identity and stored in the session. These claims should to be added back to the principal identity for every request. This done through the claims transformer as shown below:

public class ClaimsTransformer : IClaimsTransformer
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        ClaimsPrincipal principal = context.Principal;
        ClaimsIdentity identity = (ClaimsIdentity)principal.Identity;
        string claimString = NTContext.HttpContext.Session.GetString("IdentityClaims");
        if (claimString != null)
        {
            List<ClaimModel> sessionClaims = JsonConvert.DeserializeObject<List<ClaimModel>>(claimString);
            identity.AddClaims(sessionClaims.Select(sc => new Claim(sc.ClaimType, sc.ClaimValue)));
        }

        return Task.FromResult(principal);
    }
}

This ClaimsTransformer class is configured in the Startup under Configure section as shown below:

app.UseClaimsTransformation(new ClaimsTransformationOptions()
{
    Transformer = new ClaimsTransformer(),
});

app.UseIdentity();


With the above setup now the claims are stored in session when the user logs in. At every request from the user these claims will be copied from session to the identity object. Now we have overridden the default approach of using cookies with session J

8 comments:

  1. Oh, they are really hard to distinguish from each other! Thanks for the help

    ReplyDelete
  2. The saving all applications is optimal in each case. However, this also has a limit. The users will be able to leave their requests for review.

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Very interesting to read this article.I would like to thank you for the efforts you had made for writing this awesome article. This article inspired me to read more. keep it up.
    Correlation vs Covariance
    Simple linear regression

    ReplyDelete
  5. I'm not one of those readers that comments on articles often, but yours really compelled me. There's a lot of interesting content in this article that is interesting and bold.
    Best Data Science training in Mumbai

    Data Science training in Mumbai

    ReplyDelete
  6. Attend The Artificial Intelligence course From ExcelR. Practical Artificial Intelligence course Sessions With Assured Placement Support From Experienced Faculty. ExcelR Offers The Artificial Intelligence course.
    Artificial Intelligence Course

    ReplyDelete
  7. To establish a network by putting towers in a region we can use the clustering technique to find those tower locations which will ensure that all the users receive optimum signal strength.
    360digitmg data science course in bangalore

    ReplyDelete
  8. Amazing Article ! I would like to thank you for the efforts you had made for writing this awesome article. This article inspired me to read more. keep it up.
    Correlation vs Covariance
    Simple Linear Regression
    data science interview questions
    KNN Algorithm
    Logistic Regression explained

    ReplyDelete