J'utilise l'authentification OWIN pour mon projet MVC5 ..__ Ceci est ma SignInAsync
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
var AccountNo = "101";
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.UserData, AccountNo));
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, RedirectUri="Account/Index"}, identity);
}
Comme vous pouvez le constater, j’ai ajouté AccountNo
à la liste des revendications.
Maintenant, comment puis-je mettre à jour cette réclamation à un moment donné de ma demande? Jusqu'à présent, j'ai ceci:
public string AccountNo
{
get
{
var CP = ClaimsPrincipal.Current.Identities.First();
var Account= CP.Claims.FirstOrDefault(p => p.Type == ClaimTypes.UserData);
return Account.Value;
}
set
{
var CP = ClaimsPrincipal.Current.Identities.First();
var AccountNo= CP.Claims.FirstOrDefault(p => p.Type == ClaimTypes.UserData).Value;
CP.RemoveClaim(new Claim(ClaimTypes.UserData,AccountNo));
CP.AddClaim(new Claim(ClaimTypes.UserData, value));
}
}
lorsque j'essaie de supprimer la revendication, j'obtiens cette exception:
La demande ' http://schemas.Microsoft.com/ws/2008/06/identity/claims/userdata : 101 'n'a pas pu être retiré. Cela ne fait pas partie de cela Identité ou c’est une réclamation appartenant au donneur d’ordre qui contient cette identité. Par exemple, le mandant sera propriétaire de la réclamation lorsque créer un GenericPrincipal avec des rôles. Les rôles seront exposés à travers l'identité qui est passée dans le constructeur, mais pas appartenant réellement à l'identité. Une logique similaire existe pour un RolePrincipal.
Quelqu'un pourrait-il m'aider à comprendre comment mettre à jour la réclamation?
Vous pouvez créer une nouvelle ClaimsIdentity
et ensuite effectuer la mise à jour des revendications avec tel.
set {
// get context of the authentication manager
var authenticationManager = HttpContext.GetOwinContext().Authentication;
// create a new identity from the old one
var identity = new ClaimsIdentity(User.Identity);
// update claim value
identity.RemoveClaim(identity.FindFirst("AccountNo"));
identity.AddClaim(new Claim("AccountNo", value));
// tell the authentication manager to use this new identity
authenticationManager.AuthenticationResponseGrant =
new AuthenticationResponseGrant(
new ClaimsPrincipal(identity),
new AuthenticationProperties { IsPersistent = true }
);
}
J'ai créé une méthode d'extension pour ajouter/mettre à jour/lire des revendications en fonction d'un claimIdentity donné
namespace Foobar.Common.Extensions
{
public static class Extensions
{
public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value)
{
var identity = currentPrincipal.Identity as ClaimsIdentity;
if (identity == null)
return;
// check for existing claim and remove it
var existingClaim = identity.FindFirst(key);
if (existingClaim != null)
identity.RemoveClaim(existingClaim);
// add new claim
identity.AddClaim(new Claim(key, value));
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
}
public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
{
var identity = currentPrincipal.Identity as ClaimsIdentity;
if (identity == null)
return null;
var claim = identity.Claims.FirstOrDefault(c => c.Type == key);
return claim.Value;
}
}
}
et ensuite l'utiliser
using Foobar.Common.Extensions;
namespace Foobar.Web.Main.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
// add/updating claims
User.AddUpdateClaim("key1", "value1");
User.AddUpdateClaim("key2", "value2");
User.AddUpdateClaim("key3", "value3");
}
public ActionResult Details()
{
// reading a claim
var key2 = User.GetClaim("key2");
}
}
}
Une autre approche (asynchrone) consiste à utiliser UserManager et SigninManager d'Identity pour refléter la modification apportée au cookie d'identité (et éventuellement supprimer les revendications de la table db AspNetUserClaims):
// Get User and a claims-based identity
ApplicationUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
var Identity = new ClaimsIdentity(User.Identity);
// Remove existing claim and replace with a new value
await UserManager.RemoveClaimAsync(user.Id, Identity.FindFirst("AccountNo"));
await UserManager.AddClaimAsync(user.Id, new Claim("AccountNo", value));
// Re-Signin User to reflect the change in the Identity cookie
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// [optional] remove claims from claims table dbo.AspNetUserClaims, if not needed
var userClaims = UserManager.GetClaims(user.Id);
if (userClaims.Any())
{
foreach (var item in userClaims)
{
UserManager.RemoveClaim(user.Id, item);
}
}
Je reçois cette exception aussi et clarifie les choses comme ça
var identity = User.Identity as ClaimsIdentity;
var newIdentity = new ClaimsIdentity(identity.AuthenticationType, identity.NameClaimType, identity.RoleClaimType);
newIdentity.AddClaims(identity.Claims.Where(c => false == (c.Type == claim.Type && c.Value == claim.Value)));
// the claim has been removed, you can add it with a new value now if desired
AuthenticationManager.SignOut(identity.AuthenticationType);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, newIdentity);
quand j'utilise MVC5, et ajoutez la revendication ici.
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(PATAUserManager manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim(ClaimTypes.Role, this.Role));
return userIdentity;
}
lorsque je vérifie le résultat de la revendication dans la fonction SignInAsync, je ne peux pas obtenir l'utilisation de la valeur de rôle de toute façon. Mais...
une fois cette requête terminée, je peux accéder à Rôle dans une autre action (requête anther).
var userWithClaims = (ClaimsPrincipal)User;
Claim CRole = userWithClaims.Claims.First(c => c.Type == ClaimTypes.Role);
donc, je pense que peut-être asynchrone causer l'IEnumerable mis à jour derrière le processus.
En utilisant la dernière identité Asp.Net avec .net Core 2.1, je suis en mesure de mettre à jour les revendications des utilisateurs avec la logique suivante.
Enregistrez une UserClaimsPrincipalFactory
de sorte que chaque fois que SignInManager
fait sonner l'utilisateur, les revendications soient créées.
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
Implémenter un UserClaimsPrincipalFactory<TUser, TRole>
personnalisé comme ci-dessous
public class UserClaimService : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
{
private readonly ApplicationDbContext _dbContext;
public UserClaimService(ApplicationDbContext dbContext, UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{
_dbContext = dbContext;
}
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
// Get user claims from DB using dbContext
// Add claims
((ClaimsIdentity)principal.Identity).AddClaim(new Claim("claimType", "some important claim value"));
return principal;
}
}
Plus tard dans votre application lorsque vous modifiez quelque chose dans la base de données et que vous souhaitez en tenir compte à votre utilisateur authentifié et connecté, procédez comme suit:
var user = await _userManager.GetUserAsync(User);
await _signInManager.RefreshSignInAsync(user);
Cela garantit que l'utilisateur peut voir les informations mises à jour sans avoir besoin de se reconnecter. Je mets cela juste avant de renvoyer le résultat dans le contrôleur afin que, une fois l'opération terminée, le tout soit actualisé en toute sécurité.
Au lieu d'éditer les revendications existantes et de créer des conditions de concurrence pour les cookies sécurisés, etc., vous vous connectez simplement à l'utilisateur et actualisez l'état :)
Plusieurs cookies, plusieurs revendications
public class ClaimsCookie
{
private readonly ClaimsPrincipal _user;
private readonly HttpContext _httpContext;
public ClaimsCookie(ClaimsPrincipal user, HttpContext httpContext = null)
{
_user = user;
_httpContext = httpContext;
}
public string GetValue(CookieName cookieName, KeyName keyName)
{
var principal = _user as ClaimsPrincipal;
var cp = principal.Identities.First(i => i.AuthenticationType == ((CookieName)cookieName).ToString());
return cp.FindFirst(((KeyName)keyName).ToString()).Value;
}
public async void SetValue(CookieName cookieName, KeyName[] keyName, string[] value)
{
if (keyName.Length != value.Length)
{
return;
}
var principal = _user as ClaimsPrincipal;
var cp = principal.Identities.First(i => i.AuthenticationType == ((CookieName)cookieName).ToString());
for (int i = 0; i < keyName.Length; i++)
{
if (cp.FindFirst(((KeyName)keyName[i]).ToString()) != null)
{
cp.RemoveClaim(cp.FindFirst(((KeyName)keyName[i]).ToString()));
cp.AddClaim(new Claim(((KeyName)keyName[i]).ToString(), value[i]));
}
}
await _httpContext.SignOutAsync(CookieName.UserProfilCookie.ToString());
await _httpContext.SignInAsync(CookieName.UserProfilCookie.ToString(), new ClaimsPrincipal(cp),
new AuthenticationProperties
{
IsPersistent = bool.Parse(cp.FindFirst(KeyName.IsPersistent.ToString()).Value),
AllowRefresh = true
});
}
public enum CookieName
{
CompanyUserProfilCookie = 0, UserProfilCookie = 1, AdminPanelCookie = 2
}
public enum KeyName
{
Id, Name, Surname, Image, IsPersistent
}
}
Pour supprimer les détails de la demande de la base de données, nous pouvons utiliser le code ci-dessous. De plus, nous devons nous reconnecter pour mettre à jour les valeurs des cookies.
// create a new identity
var identity = new ClaimsIdentity(User.Identity);
// Remove the existing claim value of current user from database
if(identity.FindFirst("NameOfUser")!=null)
await UserManager.RemoveClaimAsync(applicationUser.Id, identity.FindFirst("NameOfUser"));
// Update customized claim
await UserManager.AddClaimAsync(applicationUser.Id, new Claim("NameOfUser", applicationUser.Name));
// the claim has been updates, We need to change the cookie value for getting the updated claim
AuthenticationManager.SignOut(identity.AuthenticationType);
await SignInManager.SignInAsync(Userprofile, isPersistent: false, rememberBrowser: false);
return RedirectToAction("Index", "Home");
if (HttpContext.User.Identity is ClaimsIdentity identity)
{
identity.RemoveClaim(identity.FindFirst("userId"));
identity.AddClaim(new Claim("userId", userInfo?.id.ToString()));
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(HttpContext.User.Identity));
}