【问题标题】:Added a claim to an existing HttpContext User添加了对现有 HttpContext 用户的声明
【发布时间】:2021-03-25 12:53:23
【问题描述】:

我正在开发一个带有端点的 ASP.NET Core 3.1 Web API,用于向现有用户身份添加新声明。声明成功添加到身份,但是,在后续请求中,添加的声明不在声明集合中,因此不可用。我还尝试添加一个新身份,为其分配声明,类似地在后续请求中,添加的身份不在身份集合中。有什么想法吗?

var claims = new List<Claim>()
{
    new Claim("token","value")
}

var identity = httpContextAccessor.HttpContext.User.Identities.FirstOrDefault();
identity.AddClaims(claims);

【问题讨论】:

  • HttpContext 对于单个请求是唯一的。为请求 (a) 的身份添加声明不会对后续请求 (b) 执行任何操作。

标签: asp.net .net asp.net-core .net-core asp.net-core-webapi


【解决方案1】:

要为现有 HttpContext 用户保留新添加的声明,您可以实现自定义 CustomClaimsPrincipalFactory。执行以下步骤:

public class AppUser : IdentityUser
{
    public string CompanyName { get; set; }
    public string DisplayName { get; set; }
}

public static class IdentityExtensions
{
    public static string FullName(this IIdentity identity)   //@User.Identity.FullName()
    {
        var claim = ((ClaimsIdentity)identity).FindFirst("DisplayName");
        // Test for null to avoid issues during local testing
        return (claim != null) ? claim.Value : string.Empty;
    }

    public static string GetCompanyName(this IIdentity identity)
    {
        if (identity == null)
            throw new ArgumentNullException(nameof(identity));

        var claim = ((ClaimsIdentity)identity).FindFirst("CompanyName");
        // Test for null to avoid issues during local testing
        return (claim != null) ? claim.Value : string.Empty;
    }
}

public class CustomClaimsPrincipalFactory : UserClaimsPrincipalFactory<AppUser, IdentityRole>
{
    public CustomClaimsPrincipalFactory(UserManager<AppUser> userManager, RoleManager<IdentityRole> roleManager,
        IOptions<IdentityOptions> optionsAccessor)
        : base(userManager, roleManager, optionsAccessor)
    {
    }

    public override async Task<ClaimsPrincipal> CreateAsync(AppUser user)
    {
        if (user == null)
            throw new ArgumentNullException(nameof(user));

        var principal = await base.CreateAsync(user);

        // Add your claims here
        ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("CompanyName", user.CompanyName));
        ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("DisplayName", user.DisplayName));

        return principal;
    }
}

注册 CustomClaimsPrincipalFactory

    public void Configure(IServiceCollection services)
    {
        ...
            services.AddScoped<IUserClaimsPrincipalFactory<AppUser>, CustomClaimsPrincipalFactory>();
        });
    }

【讨论】:

    【解决方案2】:

    您需要使用更新的ClaimsIdentity 致电_signInManager.Context.SignInAsync

    这是一个工作演示:

    1.用新ClaimsIdentity登录的扩展:

    public class CustomClaimsCookieSignInHelper<TIdentityUser> where TIdentityUser : IdentityUser
    {
        private readonly SignInManager<TIdentityUser> _signInManager;
    
        public CustomClaimsCookieSignInHelper(SignInManager<TIdentityUser> signInManager)
        {
            _signInManager = signInManager;
        }
    
        public async Task SignInUserAsync(ClaimsIdentity claimsIdentity)
        {
            await _signInManager.Context.SignInAsync(IdentityConstants.ApplicationScheme, new ClaimsPrincipal(claimsIdentity));
        }
    
    }
    

    2.注册CustomClaimsCookieSignInHelper&lt;TIdentityUser&gt;:

    services.AddTransient<CustomClaimsCookieSignInHelper<IdentityUser>>();
    

    3.更新用户声明:

    public class IndexModel : PageModel
    {
        private readonly CustomClaimsCookieSignInHelper<IdentityUser> _signInHelper;
    
        public IndexModel(CustomClaimsCookieSignInHelper<IdentityUser> signInHelper)
        {
            _signInHelper = signInHelper;            
        }       
    
        public async Task<IActionResult> OnGetAsync()
        {
            var claims = new List<Claim>()
            {
                new Claim("token","value")
            };
    
            var identity = HttpContext.User.Identities.FirstOrDefault();
            identity.AddClaims(claims);
            await _signInHelper.SignInUserAsync(identity);
            return Page();
        }
    }
    

    顺便说一句,如果您使用jwt authentication,当服务器端使用令牌获取 API 调用时,AddJwtBearer 将解码令牌、验证令牌并使用户经过身份验证,您可以在 OnTokenValidated 或自定义中添加新声明中间件。但声明不会在下一次 api 调用中持续存在。因此,如果您想在另一个请求中获取更新的声明,则必须发出新令牌。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-25
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      • 1970-01-01
      • 2017-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多