Compilé algunas respuestas de aquí en la clase ClaimsManager reutilizable con mis adiciones.
Los reclamos persistieron, la cookie del usuario se actualizó, el inicio de sesión se actualizó.
Tenga en cuenta que ApplicationUser se puede sustituir por IdentityUser si no personalizó el anterior. Además, en mi caso, debe tener una lógica ligeramente diferente en el entorno de desarrollo, por lo que es posible que desee eliminar la dependencia de IWebHostEnvironment.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using YourMvcCoreProject.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Hosting;
namespace YourMvcCoreProject.Identity
{
public class ClaimsManager
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IWebHostEnvironment _env;
private readonly ClaimsPrincipalAccessor _currentPrincipalAccessor;
public ClaimsManager(
ClaimsPrincipalAccessor currentPrincipalAccessor,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IWebHostEnvironment env)
{
_currentPrincipalAccessor = currentPrincipalAccessor;
_userManager = userManager;
_signInManager = signInManager;
_env = env;
}
public async Task AddUpdateClaim(string claimType, string claimValue, bool refreshSignin = true)
{
await AddClaim(
_currentPrincipalAccessor.ClaimsPrincipal,
claimType,
claimValue,
async user =>
{
await RemoveClaim(_currentPrincipalAccessor.ClaimsPrincipal, user, claimType);
},
refreshSignin);
}
public async Task AddClaim(string claimType, string claimValue, bool refreshSignin = true)
{
await AddClaim(_currentPrincipalAccessor.ClaimsPrincipal, claimType, claimValue, refreshSignin);
}
public async Task AddClaim(ClaimsPrincipal principal, string claimType, string claimValue, bool refreshSignin = true)
{
await AddClaim(
principal,
claimType,
claimValue,
async user =>
{
if (_env.IsDevelopment())
await RemoveClaim(principal, user, claimType);
if (GetClaim(principal, claimType) != null)
throw new ClaimCantBeReassignedException(claimType);
},
refreshSignin);
}
public async Task RemoveClaims(IEnumerable<string> claimTypes, bool refreshSignin = true)
{
await RemoveClaims(_currentPrincipalAccessor.ClaimsPrincipal, claimTypes, refreshSignin);
}
public async Task RemoveClaims(ClaimsPrincipal principal, IEnumerable<string> claimTypes, bool refreshSignin = true)
{
AssertAuthenticated(principal);
foreach (var claimType in claimTypes)
{
await RemoveClaim(principal, claimType);
}
if (refreshSignin)
await _signInManager.RefreshSignInAsync(await _userManager.GetUserAsync(principal));
}
public async Task RemoveClaim(string claimType, bool refreshSignin = true)
{
await RemoveClaim(_currentPrincipalAccessor.ClaimsPrincipal, claimType, refreshSignin);
}
public async Task RemoveClaim(ClaimsPrincipal principal, string claimType, bool refreshSignin = true)
{
AssertAuthenticated(principal);
var user = await _userManager.GetUserAsync(principal);
await RemoveClaim(principal, user, claimType);
if (refreshSignin)
await _signInManager.RefreshSignInAsync(user);
}
private async Task AddClaim(ClaimsPrincipal principal, string claimType, string claimValue, Func<ApplicationUser, Task> processExistingClaims, bool refreshSignin)
{
AssertAuthenticated(principal);
var user = await _userManager.GetUserAsync(principal);
await processExistingClaims(user);
var claim = new Claim(claimType, claimValue);
ClaimsIdentity(principal).AddClaim(claim);
await _userManager.AddClaimAsync(user, claim);
if (refreshSignin)
await _signInManager.RefreshSignInAsync(user);
}
private async Task RemoveClaim(ClaimsPrincipal principal, ApplicationUser user, string claimType)
{
AssertAuthenticated(principal);
var identity = ClaimsIdentity(principal);
var claims = identity.FindAll(claimType).ToArray();
if (claims.Length > 0)
{
await _userManager.RemoveClaimsAsync(user, claims);
foreach (var c in claims)
{
identity.RemoveClaim(c);
}
}
}
private static Claim GetClaim(ClaimsPrincipal principal, string claimType)
{
return ClaimsIdentity(principal).FindFirst(claimType);
}
private static void AssertAuthenticated(ClaimsPrincipal principal)
{
if (!principal.Identity.IsAuthenticated)
throw new InvalidOperationException("User should be authenticated in order to update claims");
}
private static ClaimsIdentity ClaimsIdentity(ClaimsPrincipal principal)
{
return (ClaimsIdentity) principal.Identity;
}
}
public class ClaimCantBeReassignedException : Exception
{
public ClaimCantBeReassignedException(string claimType) : base($"{claimType} can not be reassigned")
{
}
}
public class ClaimsPrincipalAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ClaimsPrincipalAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public ClaimsPrincipal ClaimsPrincipal => _httpContextAccessor.HttpContext.User;
}
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddTransient<ClaimsPrincipalAccessor>();
services.AddTransient<ClaimsManager>();
}
}
}
SignInManager.SignInAsync
para actualizar el valor del reclamo. Vea esta pregunta