Как обновить заявку в Identity ASP.NET?
Я использую аутентификацию OWIN для своего проекта MVC5.
Это мой 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);
}
Как вы можете видеть, я добавил AccountNo
в список претензий.
Теперь, как я могу обновить эту претензию в какой-то момент своего приложения? Пока у меня есть это:
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));
}
}
когда я пытаюсь удалить заявку, я получаю это исключение:
Претензия 'http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata: 101 'не удалось удалить. Это либо не является частью этого Идентичность или это требование, которое принадлежит Принципалу, которое содержит эта Идентичность. Например, Принципал будет владеть выражением, когда создавая GenericPrincipal с ролями. Роли будут выставлены через Identity, который передается в конструкторе, но не фактически принадлежащих Identity. Подобная логика существует для RolePrincipal.
Может ли кто-нибудь помочь мне выяснить, как обновить заявку?
Ответы
Ответ 1
Вы можете создать новый ClaimsIdentity
, а затем выполнить обновление с такими сообщениями.
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 }
);
}
Ответ 2
Я создал метод расширения для добавления/обновления/чтения претензий на основе заданного параметра ClaimsIdentity
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;
}
}
}
а затем использовать его
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");
}
}
}
Ответ 3
Другой (асинхронный) подход, используя Identity UserManager и SigninManager, чтобы отразить изменение в файле cookie Identity (и, возможно, удалить претензии из таблицы db table 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);
}
}
Ответ 4
Я тоже получаю это исключение и очищаю вещи, подобные этому
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);
Ответ 5
когда я использую MVC5 и добавляю здесь заявку.
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;
}
когда я проверяю результат претензии в функции SignInAsync, я не могу использовать значение роли. Но...
после завершения этого запроса я могу получить доступ к роли в другом действии (запрос пыльника).
var userWithClaims = (ClaimsPrincipal)User;
Claim CRole = userWithClaims.Claims.First(c => c.Type == ClaimTypes.Role);
поэтому, я думаю, возможно, асинхронный вызов IEnumerable, обновленный за процессом.
Ответ 6
Метод расширения отлично подойдет для меня с одним исключением: если пользователь выходит из системы, то старые наборы заявок все еще существуют, поэтому с крошечной модификацией, поскольку при прохождении usermanager через все работает отлично, и вам не нужно выходить из системы и входить в систему.
Я не могу ответить напрямую, поскольку моя репутация была разочарована: (
public static class ClaimExtensions
{
public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value, ApplicationUserManager userManager)
{
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)
{
RemoveClaim(currentPrincipal, key, userManager);
}
// add new claim
var claim = new Claim(key, value);
identity.AddClaim(claim);
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
//Persist to store
userManager.AddClaim(identity.GetUserId(),claim);
}
public static void RemoveClaim(this IPrincipal currentPrincipal, string key, ApplicationUserManager userManager)
{
var identity = currentPrincipal.Identity as ClaimsIdentity;
if (identity == null)
return ;
// check for existing claim and remove it
var existingClaims = identity.FindAll(key);
existingClaims.ForEach(c=> identity.RemoveClaim(c));
//remove old claims from store
var user = userManager.FindById(identity.GetUserId());
var claims = userManager.GetClaims(user.Id);
claims.Where(x => x.Type == key).ToList().ForEach(c => userManager.RemoveClaim(user.Id, c));
}
public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
{
var identity = currentPrincipal.Identity as ClaimsIdentity;
if (identity == null)
return null;
var claim = identity.Claims.First(c => c.Type == key);
return claim.Value;
}
public static string GetAllClaims(this IPrincipal currentPrincipal, ApplicationUserManager userManager)
{
var identity = currentPrincipal.Identity as ClaimsIdentity;
if (identity == null)
return null;
var claims = userManager.GetClaims(identity.GetUserId());
var userClaims = new StringBuilder();
claims.ForEach(c => userClaims.AppendLine($"<li>{c.Type}, {c.Value}</li>"));
return userClaims.ToString();
}
}
Ответ 7
Здесь вы идете:
var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
var claim = (from c in user.Claims
where c.Type == ClaimTypes.UserData
select c).Single();
identity.RemoveClaim(claim);
взято из здесь.