I have an application that I need to control the access of the users that are according to the profile of each one. Empresa
, Filial
.
In the User entity I have added the fields referring to these two other entities and in them will be the information that represents 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 GenerateUserIdentityAsync
method.
And then I created a IdentityManager
class to help get this information and update it when I need it.
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 Claims values in IPrincipal I execute authenticationManager.SignIn
.
And this works perfectly throughout the application until the time for validating the cookie, as configured in Identity, is zeroed and validation is redone:
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))
}
});
Then every 30 minutes cookies are revalidated / rebuilt as the GenerateUserIdentityAsync
method of the User class, as also configured in the above code, losing the data that was previously included.
The issue is that users with a company profile can choose to switch to the% profile of%, choosing the affiliate, to be able to perform operations for it.
Because I do not have access to the current claims information within the Filial
method, I can not re-place them in Claims.
My question is:
How can I do not to lose the current Claims information on cookie revalidations made at 30-minute intervals (as configured)?
I'm using VisualStudio 2015 Community with .Net 4.6. Thanks!