How do I not lose the data included in Claims in the revalidations of Cookies?

Asked

Viewed 97 times

2

I have an application that needs to control the access of users who are according to the profile of each one. Empresa, Filial.

In the User entity I added the fields referring to these other two entities and in them will be the information representing each one and its access profile.

public class Usuario : IdentityUser
{
    public int EmpresaId { get; set; }
    public int? FilialId { get; set; }

    public virtual Empresa Empresa { get; set; }
    public virtual Filial Filial { get; set; }

    public Perfil Perfil { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<Usuario> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

        userIdentity.AddClaim(new Claim(CustomClaimTypes.EMPRESA_ID, EmpresaId.ToString()));
        userIdentity.AddClaim(new Claim(CustomClaimTypes.FILIAL_ID, FilialId?.ToString() ?? ""));
        userIdentity.AddClaim(new Claim(CustomClaimTypes.PERFIL, Perfil.ToString());

        return userIdentity;
    }
}

To control the profile within the application I load and get the information in the user’s Claims, as shown in the method GenerateUserIdentityAsync.

And then I created a class IdentityManager to help obtain such information and update it when needed.

public class IdentityManager
{
    public IdentityManager(IIdentity identity)
    {
        Identity = identity as ClaimsIdentity;
    }

    protected ClaimsIdentity Identity { get; set; }

    public int EmpresaId
    {
        get { return GetClaimValue(CustomClaimTypes.EMPRESA_ID); }
        set { SetClaim(CustomClaimTypes.EMPRESA_ID, value.ToString()); }
    }        

    public int? FilialId
    {
        get { return GetClaimValue(CustomClaimTypes.FILIAL_ID); }
        set { SetClaim(CustomClaimTypes.FILIAL_ID, value.ToString()); }
    }

    public Perfil Perfil
    {
        get { return (Perfil)Enum.Parse(typeof(Perfil), GetClaimValue(CustomClaimTypes.PERFIL)); }
        set { SetClaim(CustomClaimTypes.PERFIL, value.ToString()); }
    }

    public void Update()
    {
        var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
        authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, Identity);
    }

    private int GetClaimValue(string claimType)
    {
        int id;
        int.TryParse(Identity.FindFirstValue(claimType), out id);
        return id;
    }

    private void SetClaim(string claimType, string value)
    {
        var claim = Identity.FindFirst(claimType);
        if (claim != null) Identity.TryRemoveClaim(claim);
        Identity.AddClaim(new Claim(claimType, value ?? ""));
    }
}

To update the new values of Claims in Iprincipal I run authenticationManager.SignIn.

And this works perfectly throughout the application until the time for cookie validation, as set in Identity, Zera and validation is remade:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity =
            SecurityStampValidator.OnValidateIdentity<AppUserManager, Usuario>(

                TimeSpan.FromMinutes(30), // <-- Revalida os cookies de 30 em 30 minutos

                (manager, user) => user.GenerateUserIdentityAsync(manager))
    }
});

So every 30 minutes cookies are revalidated/rebuilt as a method GenerateUserIdentityAsync of the User class, as also configured in the above code, losing the data that were previously included.

The issue is that users with company profile can choose to change to the profile Filial, choosing the subsidiary, in order to be able to carry out operations for it.

For not having access to current information of the Claims within the method GenerateUserIdentityAsync, I can’t get them back in Claims.

My question is:
How could I avoid losing the current information of Claims in the revalidations of cookies made at 30 minute intervals (as per configuration)?

I’m using Visualstudio 2015 Community with . Net 4.6.
Grateful!

1 answer

1

The problem with revalidation is that you don’t store session information anywhere. It’s important to understand that Claims are different from session data.

There are two things you can do:

  1. Serialize the list of Claims and keep it within Session;
  2. Use a key-value server such as Redis and bring this user preference data there (also by automatically storing the data and storing it as a string only).

Be whatever path you choose to follow, before you define the Claims, make a check of the existence of the string and set the values first by string if this is possible. Otherwise, you simply re-fill the list of Claims, as is already done.

  • 1

    I was curious about the table AspNetUserClaims if you can’t store in it. Honestly, I haven’t seen it being used yet. Thank you for the answer!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.