【问题标题】:How to update a claim in ASP.NET Identity?如何更新 ASP.NET Identity 中的声明?
【发布时间】:2014-08-26 13:36:59
【问题描述】:

我正在为我的 MVC5 项目使用 OWIN 身份验证。 这是我的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' 无法删除。它要么不是这个的一部分 身份或它是由包含的 Principal 拥有的声明 这个身份。例如,委托人将在以下情况下拥有索赔 创建具有角色的 GenericPrincipal。角色将被曝光 通过在构造函数中传递的身份,但不是 实际归身份所有。类似的逻辑存在于 角色主体。

如何删除和更新声明?

【问题讨论】:

  • 如果您在Claim中存储用户信息并且想要更新Claim,一旦用户信息发生变化,您可以调用:SignInManager.SignInAsync刷新Claim的值。见this question

标签: c# asp.net asp.net-mvc asp.net-mvc-4 asp.net-web-api


【解决方案1】:

我创建了一个扩展方法来根据给定的 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.GetClaimValue("key2");          
        }
    }
}

【讨论】:

  • 最后。我对此有另一种解决方案,它似乎正在工作......主要是。但最终切换到这种方法,因为它似乎总是有效。谢谢!
  • 有人对 Asp.Net One Core 有相同的解决方案吗?
  • 这似乎只适用于当前应用程序。我想更新 SSO 服务器发出的 cookie,以便其他应用程序也可以访问它们。知道怎么做吗?谢谢
  • var claim = identity.Claims.First(c => c.Type == key); return claim.Value;应该是 var claim = identity.Claims.FirstOrDefault(c => c.Type == key);退货索赔?。价值;
  • 如何使用 .net core 2.2 做到这一点?不推荐使用身份验证属性。
【解决方案2】:

您可以创建一个新的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 }
        );
}

【讨论】:

  • 您可以更新声明,但仍需要使用更新后的身份注销用户并登录。
  • 不,它不会注销用户,我们只是更新用户的cookie
  • 请记住,这只会更新身份。如果您想存储这些声明并根据请求自动加载它们,您还需要用户管理器来删除和更新它们。花了我一些时间! :(
  • 如果我根本没有 cookie 并且只使用 accessToken 怎么办?在我的情况下,下一个请求的声明与更改前相同。更新我拥有的声明的唯一方法是注销用户并要求他再次登录:-(
  • 这似乎只适用于当前应用程序。我想更新 SSO 服务器发出的 cookie,以便其他应用程序也可以访问它们。知道怎么做吗?谢谢
【解决方案3】:

另一种(异步)方法,使用 Identity 的 UserManager 和 SigninManager 来反映 Identity cookie 中的更改(并可选择从 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);
  }
}

【讨论】:

  • 对我来说,这里的线索是设置声明之后执行SignInAsync()
  • 感谢您提供有关从数据库中删除声明的提示。让我意识到我需要自己清理一下。
【解决方案4】:

将最新的 Asp.Net Identity 与 .net core 2.1 结合使用,我能够使用以下逻辑更新用户声明。

  1. 注册一个UserClaimsPrincipalFactory,这样每次SignInManager 唱用户时,就会创建声明。

    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
    
  2. 实现自定义UserClaimsPrincipalFactory&lt;TUser, TRole&gt;,如下所示

    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;
        }
    }
    
  3. 稍后在您的应用程序中,当您更改数据库中的某些内容并希望将其反映给您的经过身份验证和登录的用户时,以下几行可以实现此目的:

    var user = await _userManager.GetUserAsync(User);
    await _signInManager.RefreshSignInAsync(user);
    

这确保用户无需再次登录即可查看最新信息。我把它放在控制器中返回结果之前,这样当操作完成时,一切都会安全地刷新。

您无需编辑现有声明并为安全 cookie 等创建竞争条件,您只需静默登录用户并刷新状态 :)

【讨论】:

  • 谢谢,遇到了同样的问题,此解决方案更适合更新已签名用户的声明。
  • 谢谢!在 net core 3.1 中也面临同样的问题
  • 对我来说,我只添加了 Step-3 行,它对我来说工作正常。谢谢@Mahmut C
【解决方案5】:

我也遇到了这个异常并像这样清理了一些事情

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);

【讨论】:

    【解决方案6】:

    将这里的一些答案编译到 re-usable ClaimsManager 类中,并附上我的补充。

    声明得以保留,用户 cookie 已更新,登录已刷新。

    请注意,如果您没有自定义前者,ApplicationUser 可以替换为 IdentityUser。同样在我的情况下,它需要在开发环境中具有稍微不同的逻辑,因此您可能需要删除 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;
            }
    
            /// <param name="refreshSignin">Sometimes (e.g. when adding multiple claims at once) it is desirable to refresh cookie only once, for the last one </param>
            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);
            }
    
            /// <summary>
            /// At certain stages of user auth there is no user yet in context but there is one to work with in client code (e.g. calling from ClaimsTransformer)
            /// that's why we have principal as param
            /// </summary>
            public async Task AddClaim(ClaimsPrincipal principal, string claimType, string claimValue, bool refreshSignin = true)
            {
                await AddClaim(
                    principal,
                    claimType,
                    claimValue, 
                    async user =>
                    {
                        // allow reassignment in dev
                        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);
                }
                // reflect the change in the Identity cookie
                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);
                // reflect the change in the Identity cookie
                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);
                // reflect the change in the Identity cookie
                if (refreshSignin)
                    await _signInManager.RefreshSignInAsync(user);
            }
    
            /// <summary>
            /// Due to bugs or as result of debug it can be more than one identity of the same type.
            /// The method removes all the claims of a given type.
            /// </summary>
            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);    
            }    
    
            /// <summary>
            /// This kind of bugs has to be found during testing phase
            /// </summary>
            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;
    }
    
    // to register dependency put this into your Startup.cs and inject ClaimsManager into Controller constructor (or other class) the in same way as you do for other dependencies    
    public class Startup
    {
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<ClaimsPrincipalAccessor>();
            services.AddTransient<ClaimsManager>();
        }
    }
    

    }

    【讨论】:

      【解决方案7】:

      当我使用 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 在进程后面更新。

      【讨论】:

        【解决方案8】:

        您可以通过实现CookieAuthenticationEvents 类并覆盖ValidatePrincipal 来更新当前用户的声明。在那里,您可以删除旧声明,添加新声明,然后使用 CookieValidatePrincipalContext.ReplacePrincipal 替换主体。这不会影响存储在数据库中的任何声明。这是使用 ASP.NET Core Identity 2.2。

        public class MyCookieAuthenticationEvents : CookieAuthenticationEvents
        {
            string newAccountNo = "102";
        
            public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
            {
                // first remove the old claim
                var claim = context.Principal.FindFirst(ClaimTypes.UserData);
                if (claim != null)
                {
                    ((ClaimsIdentity)context.Principal.Identity).RemoveClaim(claim);
                }
        
                // add the new claim
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim(ClaimTypes.UserData, newAccountNo));
        
                // replace the claims
                context.ReplacePrincipal(context.Principal);
                context.ShouldRenew = true;
        
                return Task.CompletedTask;
            }
        }
        

        你需要在Startup.cs注册事件类:

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<MyCookieAuthenticationEvents>();
        
            services.ConfigureApplicationCookie(o =>
            {
                o.EventsType = typeof(MyCookieAuthenticationEvents);
            });
        }
        

        您可以将服务注入事件类以访问新的AccountNo 值,但根据this page 上的警告,您应该避免做任何过于昂贵的事情:

        警告

        这里描述的方法是在每个请求上触发的。证实 针对每个请求的所有用户的身份验证 cookie 可能会导致 应用的性能损失很大。

        【讨论】:

        • 谢谢,这在 asp.net core 3.1 中非常适合我!
        【解决方案9】:

        我正在使用 .net core 2.2 应用程序并使用以下解决方案: 在我的 statup.cs 中

        public void ConfigureServices(IServiceCollection services)
                {
                ...
                   services.AddIdentity<IdentityUser, IdentityRole>(options =>
                       {
                          ...
                       })
                       .AddEntityFrameworkStores<AdminDbContext>()
                       .AddDefaultTokenProviders()
                       .AddSignInManager();
        
        

        用法

          private readonly SignInManager<IdentityUser> _signInManager;
        
        
                public YourController(
                                            ...,
        SignInManager<IdentityUser> signInManager)
                {
                   ...
                    _signInManager = signInManager;
                }
        
         public async Task<IActionResult> YourMethod() // <-NOTE IT IS ASYNC
                {
                        var user = _userManager.FindByNameAsync(User.Identity.Name).Result;
                        var claimToUse = ClaimsHelpers.CreateClaim(ClaimTypes.ActiveCompany, JsonConvert.SerializeObject(cc));
                        var claimToRemove = _userManager.GetClaimsAsync(user).Result
                            .FirstOrDefault(x => x.Type == ClaimTypes.ActiveCompany.ToString());
                        if (claimToRemove != null)
                        {
                            var result = _userManager.ReplaceClaimAsync(user, claimToRemove, claimToUse).Result;
                            await _signInManager.RefreshSignInAsync(user); //<--- THIS
                        }
                        else ...
                      
        

        【讨论】:

          【解决方案10】:

          目前对我来说更新现有声明的最简单解决方案是:

          //updating user data        
          await signInManager.SignOutAsync();
          await signInManager.SignInAsync(user, false);
          

          【讨论】:

          • 这个行得通,我终于放弃了IUserStore、SignInManager、UserManager、ClaimsPrincipalAccessor、ClaimsManager……真是复杂的东西
          • 它对我不起作用,我在调用 SignInAsync 后没有在 HttpContext.User.Claims 中看到新用户声明。你有什么想法吗?
          • @Caner 和我一样。有基于数据库中用户数据的索赔。我更新了它们,然后重新注册了用户,以便应用程序自行更新声明。您也可以手动更新声明,但是您还必须手动更新 cookie 等,但是我还没有弄清楚如何去做,我不能告诉你。附:对不起谷歌翻译)
          【解决方案11】:

          感谢这个关于 .NET 4/OWIN 的问题,但为了帮助搜索者寻找 .NET 5 或更高版本的等效版本,这里有一些示例代码。

          我相信你可以改进它,但它是使用 Microsoft.AspNetCore.Identity 中的 UserManagerSignInManager 的有效启动器。

          // Get the user first first. 
          var claims = await _userManager.GetClaimsAsync(user);
          var givenNameClaim = claims.FirstOrDefault(r => r.Type == JwtClaimTypes.GivenName);
          
          IdentityResult result = null;
          
          if (givenNameClaim != null)
          {
              result = await _userManager.ReplaceClaimAsync(user, givenNameClaim, new Claim(JwtClaimTypes.GivenName, "<newvalue>"));
          }
          else
          {
              result = await _userManager.AddClaimAsync(user, new Claim(JwtClaimTypes.GivenName, "<newvalue>"));
          }
          
          if (result.Errors.Any())
          {
              // TODO: List errors here;
          }
          else
          {
              await _signInManager.RefreshSignInAsync(user); // refresh the login, so it takes effect immediately.
          }
          

          【讨论】:

          • 我如何首先获取 UserManager 和第一行的用户?
          • 这将依赖注入到控制器或类中。也许像this post 这样的东西可能会有所帮助。
          【解决方案12】:

          要从数据库中删除索赔详细信息,我们可以使用以下代码。另外,我们需要重新登录才能更新 cookie 值

           // 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");
          

          【讨论】:

            【解决方案13】:

            多个 Cookie,多个声明

            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
                    }
                }
            

            【讨论】:

              【解决方案14】:
                  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));
                      }
              

              【讨论】:

              【解决方案15】:

              扩展方法对我来说非常有用,但有一个例外是,如果用户在那里注销,旧的声明集仍然存在,因此只需稍作修改,如将 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();
                  }
              
              
              }
              

              【讨论】:

                【解决方案16】:

                给你:

                            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);
                

                取自here.

                【讨论】:

                  猜你喜欢
                  • 2016-10-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-02-18
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-03-11
                  • 2018-05-17
                  • 2016-11-09
                  相关资源
                  最近更新 更多