我使用IdentityServer4作为OIDC提供程序和ASP.NET Core 2.0。
我已经浏览了几篇帖子,以确保IdentityServer发布的声明最终出现在ClaimsPrincipal(即Auth Cookie)中,并设法通过ClaimsAction过滤实现了这一点。
然而,我的问题是。。。当使用ASP.NET Identity(和EF后备存储)运行IdentityServer时,如何将ASP.NET Identity属性映射到IDS4返回的声明。默认情况下,IDS4会返回以下声明:。。。
- "sub":来自IdentityUser.Id
- "name":来自IdentityUser.UserName
- "preferred_username":来自IdentityUser.username
- "电子邮件":来自IdentityUser.email
- "email_verified":来自IdentityUser.EmailConfirmed
我问这个问题的原因是,我想映射
- "given_name":来自IdentityUser.FirstName(扩展属性)
- "family_name":来自IdentityUser.LastName(扩展属性)
因为IDS4在请求PROFILE作用域时默认不会执行此操作。
此外,我想问一下存储用户属性的最佳实践是什么。使用ASP.NET Identity DB时,会创建两个表。。。
- AspNetUsers
- AspNetUserClaims
因此,添加其他用户属性作为。。。
- IdentityUser上的属性(作为新字段添加到AspNetUsers)或
- AspNetUserClaims中的其他声明(可以在注册或登录时使用UserManager.AddClaimAsync()添加这些声明)
如何将用户属性映射到声明
正如您自己回答的那样,应该以编程方式映射扩展属性。
- 如果要向
AspNetUsers
表中添加列,请扩展IdentityUser
类(例如public class MyApplicationUser : IdentityUser
),然后添加自定义属性(例如FirstName
)。这从本质上改变了模型。为了确保EF将您的模型更改写入DB表,您需要用新的MyApplicationUser
类扩展IdentityDbContext
类- 如果要将用户的自定义声明(例如
hair_color
)添加到AspNetUserClaims
表中,则需要调用userManager.AddClaimAsync()
。您可以在注册过程或登录过程中使用表单中的数据,或从谷歌、脸书、推特等外部授权提供商处收到的声明中进行此操作
但是,正如你在我对你的附加问题的回答中所读到的,我认为你不应该绘制它们的地图,而应该立即让它们声明。
存储用户属性的位置
我发现您的附加问题更有趣:要向AspNetUsers
添加哪些属性,何时向AspNetUserClaims
添加?
编辑:更新的答案
经过一些讨论,我可能会说,主要考虑因素是:
-
ASP.NET标识是用户数据主要来源的属性应为强类型数据库列(通常在
AspNetUsers
中),并在创建主体时传播到声明(如有必要) -
从另一个源导入和更新的属性可以立即传播到DB(
AspNetUsersClaims
)中的声明
示例:
-
如果
hair_color
是用户在此标识界面中输入和更改的属性,则将其存储在强类型数据库列中 -
如果
hair_color
是在另一个应用程序中维护并从中更新的属性,我会将其作为记录存储在声明表中
在我编写原始答案(如下)时处理的案例中,要共享的用户数据是从另一个(主要)源间接更新的,但对于身份验证详细信息,ASP.NET Identity是主要源。因此,它产生了相同的分布,但原因不同
原始答案
据我所知,经验法则是:
- (仅)用于与其他应用程序共享的数据(用户信息)应为受保护的身份资源,因此
AspNetUsersClaims
中声明了这一点 - 功能上用于身份验证的数据(身份验证信息)应该是用户(
AspNetUsers
)的一部分,因此用于身份验证、登录、恢复、2-事实等的数据(例如用户名、密码、电子邮件、电话)
示例:
- 如果您想添加
DateOfBirth
,我会将其添加到AspNetUsersClaims
(除非您打算以某种方式使用它进行身份验证/登录) - 如果要存储帐户/登录相关数据(如
accountExpiresDate
或CreatedFromIP
),请将其添加到AspNetUsers
(并扩展IdentityUser
)
因此,如果使用UserClaimsPrincipalFactory
将用户属性添加到用户声明中,则可能只是将该属性添加到了错误的表中!
TLDR
事实上,我发现了你的问题,同时我自己也在思考这个问题。我开始使用上面的经验法则,但问题不断出现,因为很多例子都不遵循这个法则。例如,微软有一个例子建议添加Name和DOB,这似乎与此相矛盾。但是,OpenID已经将这些属性(a.o.)定义为可选profile
范围中的标准声明:birthdate, name, family_name, given_name, middle_name, nickname, preferred_username
。