【问题标题】:Customizing ASP.NET Identity自定义 ASP.NET 标识
【发布时间】:2017-07-07 19:00:38
【问题描述】:

我正在使用 Identity Server 4,并且我已按如下方式自定义了我的 ASP.NET Identity 用户:

public class ApplicationUser : IdentityUser
{
    [MaxLength(100)]
    public virtual string FirstName { get; set; }

    [MaxLength(100)]
    public virtual string LastName { get; set; }
}

我看不到在哪里配置 Identity Server 4 以将这 2 个属性包含在声明集合中。我浏览了一些 Identity Server 4 示例,但没有看到任何示例。

理想情况下,我希望将这 2 个用户属性映射到 given_namefamily_name 声明。

我目前正在连接通知并查询userinfo 端点(混合流?)。所以我不确定这是身份服务器的配置还是userinfo端点的自定义?

【问题讨论】:

    标签: identityserver4


    【解决方案1】:

    为了包含您的自定义声明,您需要使用IProfileService 实现您自己的GetProfileDataAsync() 方法。每次请求用户声明时都会调用此方法。

    这是我的 IProfileService 实现。

    public class CustomProfileService : IProfileService
    {
        private readonly UserManager<User> _userManager;
    
        public CustomProfileService(UserManager<User> userManager)
        {
            _userManager = userManager;
        }
    
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var subjectId = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(subjectId);
    
            if (user == null) return;
    
            var claims = new List<Claim>
            {
                new Claim("username", user.UserName),
                new Claim("email", user.Email),
                new Claim("firstname", user.FirstName),
                new Claim("lastname", user.LastName)
            };
    
            var roles = await _userManager.GetRolesAsync(user);
            foreach (var role in roles)
            {
                claims.Add(new Claim("role", role));
            }
    
            var userClaims = await _userManager.GetClaimsAsync(user);
            foreach (var userClaim in userClaims)
            {
                claims.Add(new Claim(userClaim.Type, userClaim.Value));
            }
    
            context.IssuedClaims = claims;
        }
    
        public async Task IsActiveAsync(IsActiveContext context)
        {
            var user = await _userManager.FindByIdAsync(context.Subject.GetSubjectId());
            context.IsActive = user.IsActive;
        }
    }
    

    那么你必须在Startup.ConfigureServices()中添加下面这行

    services.AddScoped&lt;IProfileService, CustomProfileService&gt;();

    【讨论】:

    • 这看起来像是完美的解决方案,但我看不到我的自定义配置文件服务被调用过。在 ctor 和所有方法上添加断点 - 什么都没有(是的 - 它在 DI 中正确连接)
    【解决方案2】:

    我想知道为什么没有关于此的文档。这让我意识到我可能做错了。

    我没有看到作为 ASP.NET 标识的一部分创建的表 AspNetUserClaims。我在此处添加了我的索赔数据,索赔数据作为profile 的一部分通过。

    AccountController.RegisterPOST 方法中我添加了:

    var givenNameClaim = new IdentityUserClaim<string>()
    {
        ClaimType = "given_name",
        ClaimValue = model.FirstName
    };
    
    var familyNameClaim = new IdentityUserClaim<string>()
    {
        ClaimType = "family_name",
        ClaimValue = model.LastName
    };
    
    var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
    user.Claims.Add(givenNameClaim);
    user.Claims.Add(familyNameClaim);
    

    【讨论】:

    • 如果您使用 aspnet 身份来管理用户,那么这将是正确的答案。因为您已经有一个将使用这些值的 IProfileService 实现。由于我使用的是 2.1,因此在创建声明时我不得不稍作更改。 await _userManager.AddClaimsAsync(user, new List&lt;Claim&gt; { new Claim("given_name", model.FirstName), new Claim("family_name", model.LastName) });
    • 这可能会对一些做 SPA 的人有所帮助:stackoverflow.com/questions/61201244/…
    【解决方案3】:

    这是我所做的:在 AccountController.ExternalLoginCallback 我添加了这个:

    //Add claim even if client didn't ask for it
    additionalClaims.Add(new Claim(JwtClaimTypes.Email, "email@email.com"));
    

    然后我通过依赖注入我的 ProfileService 类并将声明添加到 access_token 并在 MyProfileService.GetProfileDataAsync 中添加声明,如下所示:

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var claims = new List<Claim>();
    
        Claim emailClaim = context.Subject.Claims.Where<Claim>(claim => claim.Type.Equals(JwtClaimTypes.Email)).FirstOrDefault();
    
        if (emailClaim != null)
        {
            claims.Add(emailClaim);
        }
    
        context.IssuedClaims = claims;
        return Task.FromResult(0);
    }
    

    【讨论】:

    • 谢谢,additionalClaims 来自哪里,我的方法或控制器中没有声明?
    • @AdrianThompsonPhillips 这只是我创建的new List&lt;Claim&gt;()。查看调用await HttpContext.Authentication.SignInAsync(user.SubjectId, user.Username, provider, props, additionalClaims.ToArray()); 的示例
    猜你喜欢
    • 2018-09-03
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 2017-07-26
    • 2018-04-26
    • 2019-08-07
    • 2014-04-24
    相关资源
    最近更新 更多