Ich verwende die OWIN-Authentifizierung für mein MVC5-Projekt ... Dies ist mein _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);
}
Wie Sie sehen, habe ich AccountNo
in die Anspruchsliste aufgenommen.
Wie kann ich diesen Antrag an einem bestimmten Punkt in meiner Bewerbung aktualisieren? Bisher habe ich folgendes:
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));
}
}
wenn ich versuche, die Behauptung zu entfernen, erhalte ich folgende Ausnahme:
Der Anspruch ' http://schemas.Microsoft.com/ws/2008/06/identity/claims/userdata : 101 'konnte nicht entfernt werden. Es ist entweder nicht Teil davon Identität oder ein Anspruch, der dem Auftraggeber gehört, der .__ enthält. diese Identität. Beispielsweise hat der Auftraggeber den Anspruch, wenn Erstellen eines GenericPrincipal mit Rollen. Die Rollen werden angezeigt durch die im Konstruktor übergebene Identität, jedoch nicht eigentlich im Besitz der Identität. Eine ähnliche Logik existiert für eine RolePrincipal.
Könnte mir jemand helfen, herauszufinden, wie ich den Claim aktualisieren kann?
Sie können eine neue ClaimsIdentity
erstellen und dann die Ansprüche mit solchen aktualisieren.
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 }
);
}
Ich habe eine Erweiterungsmethode zum Hinzufügen/Aktualisieren/Lesen von Ansprüchen basierend auf einer bestimmten ClaimsIdentity erstellt
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;
}
}
}
und dann zu benutzen
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");
}
}
}
Ein anderer (asynchroner) Ansatz, bei dem Identity UserManager und SigninManager verwendet werden, um die Änderung im Identity-Cookie wiederzugeben (und optional Ansprüche aus der db table AspNetUserClaims zu entfernen):
// 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);
}
}
Ich bekomme auch diese Ausnahme und klärte die Dinge so auf
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);
wenn ich MVC5 verwende, und hier den Anspruch hinzufügen.
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;
}
wenn ich das Claim-Ergebnis in der SignInAsync-Funktion überprüfe, kann ich den Rollenwert trotzdem nicht verwenden. Aber...
nachdem diese Anforderung abgeschlossen ist, kann ich auf die Rolle in einer anderen Aktion zugreifen (andere Anforderung).
var userWithClaims = (ClaimsPrincipal)User;
Claim CRole = userWithClaims.Claims.First(c => c.Type == ClaimTypes.Role);
also, ich denke, vielleicht asynchron, weil der IEnumerable hinter dem Prozess aktualisiert wurde.
Durch die Verwendung der neuesten Asp.Net-Identität mit .net Core 2.1 kann ich Benutzeransprüche mit der folgenden Logik aktualisieren.
Registrieren Sie eine UserClaimsPrincipalFactory
, so dass die Ansprüche jedes Mal erstellt werden, wenn SignInManager
den Benutzer einloggt.
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
Implementieren Sie einen benutzerdefinierten UserClaimsPrincipalFactory<TUser, TRole>
wie unten
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;
}
}
Wenn Sie später in Ihrer Anwendung etwas in der Datenbank ändern und dies Ihrem authentifizierten und angemeldeten Benutzer mitteilen möchten, wird dies durch folgende Zeilen erreicht:
var user = await _userManager.GetUserAsync(User);
await _signInManager.RefreshSignInAsync(user);
Dadurch wird sichergestellt, dass Benutzer aktuelle Informationen sehen können, ohne sich erneut anmelden zu müssen. Ich stelle dies kurz vor der Rückgabe des Ergebnisses in den Controller ein, damit nach Abschluss des Vorgangs alles sicher aktualisiert wird.
Anstatt vorhandene Ansprüche zu bearbeiten und Race-Bedingungen für sichere Cookies usw. zu erstellen, melden Sie den Benutzer einfach still an und aktualisieren den Status. :)
Mehrere Cookies, mehrere Ansprüche
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
}
}
Um die Antragsdetails aus der Datenbank zu entfernen, können Sie den folgenden Code verwenden. Außerdem müssen wir uns erneut anmelden, um die Cookie-Werte zu aktualisieren
// 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));
}