我配置了多个外部身份验证提供程序,例如Facebook,MSA等。当用户通过其中任何一个登录时,我想转换/规范化声明,并可能在将用户发送回客户端之前添加其他自定义声明,例如角色。这样,我的客户端就不必关心用户通过哪个提供程序登录,因为令牌中的所有声明都是相同的。即无需转换客户端中的声明。
我还想根据用户登录时使用的提供商来执行此操作。
我已经研究了使用UserClaimsPrincipalFactory<TUser>
(支持 DI),然后向AddClaimsPrincipalFactory
注册我的实现。这是首选方法吗?但是,我看不到使用哪个提供商在此处登录,因为身份验证方法始终Identity.Application
。此处的声明中没有任何内容表明使用了哪个提供程序。
我还考虑替换SignInManager<TUser>
然后覆盖方法SignInAsync
,但是如果我在此处更改声明,它不会反映在发送给客户端的令牌中。此外,参数authenticationMethod
在用户首次登录并完成同意和电子邮件/用户名确认屏幕时为 null。
我还想避免替换从帐户控制器调用的GetExternalLoginInfoAsync
和ExternalLoginSignInAsync
方法中自动处理的大部分代码。
我认为转换来自外部提供商的声明将是一等公民功能,但不清楚如何以及在何处执行此操作,因此它正确存储在数据库中(假设使用了 ASP.NET 核心身份)和令牌。
我发现使用IClaimsTransformation
转换声明对我有用。它似乎在所有版本的.NET Core中都可用,并且我添加/更新的信息将传递给调用IdentityServer的客户端。
请注意,可以多次调用此类,因此转换应该是幂等的。
下面是一个示例声明转换,它将given_name
替换为DEMO
public class DemoClaimsTransformator : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (!(principal.Identity is ClaimsIdentity identity))
{
return Task.FromResult(principal);
}
var existingClaim = identity.FindFirst("given_name");
if (existingClaim != null)
{
identity.RemoveClaim(existingClaim);
}
identity.AddClaim(new Claim("given_name", "DEMO"));
return Task.FromResult(principal);
}
}
我在这个博文中发现了它: https://davidwalschots.com/how-to-add-additional-claims-to-the-httpcontext-user/