Authentication ASP核心将自定义声明添加到身份验证令牌

Authentication ASP核心将自定义声明添加到身份验证令牌,authentication,asp.net-core,Authentication,Asp.net Core,我正在使用openiddict和ASP Identity,并尝试添加一个“GroupId”作为登录时返回的身份验证令牌的声明(使用/connect/token端点-请参见下面的示例)。GroupId是我的AplicationUser类中的一个属性 我曾尝试使用iclaimsstransformer,但这似乎很笨拙,我无法从ClaimsTransformationContext轻松访问UserManager 我如何通过我的iclaimsstransformer中的DI获取UserManager,或

我正在使用openiddict和ASP Identity,并尝试添加一个“GroupId”作为登录时返回的身份验证令牌的声明(使用/connect/token端点-请参见下面的示例)。GroupId是我的AplicationUser类中的一个属性

我曾尝试使用
iclaimsstransformer
,但这似乎很笨拙,我无法从ClaimsTransformationContext轻松访问UserManager

我如何通过我的
iclaimsstransformer
中的DI获取UserManager,或者只是将GroupId添加到在connect/token端点生成的令牌中

我按照这个例子建立了我的网站。这就是我想做的:

var groupGuid = User.Claims.FirstOrDefault(c => c.Type == "GroupGuid");
ASP核心将自定义声明添加到身份验证令牌

在IdP对令牌进行签名后,您不能更改令牌,因此您不能向令牌添加声明

我试过使用IClaimsTransformer,但它似乎很笨重,我 无法轻松地从服务器访问UserManager 索赔信息上下文

我想你的问题和这个github有关。总之(据我所知),若
claimtransformer
类注册为singletion,并且它的一个依赖项是作用域的或暂时的,那个么它会导致。在这种情况下,您应该使用服务定位器模式来避免捕获依赖。您的代码可能如下所示(来自@PinpointTownes的评论):

public async Task TransformAsync(claimtransformationcontext)
{
var userManager=context.context.RequestServices.GetRequiredService();
//
} 
--我对你的案子的看法--

你基本上有两种选择来实现你的目标:

当IdP生成令牌时,向令牌添加声明:

在大多数情况下,您不需要此方法,但如果您想使用它:

  • 您应该可以控制IdP,因为此选项在IdP上是可行的(据我所知,您的IdP和资源服务器是相同的,因此您可以控制IdP,但可能并不总是可行的)
  • 使用此选项时,您应该注意不一致性,因为声明存储在令牌中,并且不会获得每个请求。因此,声明的实际价值可能不同于令牌中的声明(我不喜欢角色、权限、组等,因为这些声明可以随时更改)
p、 s:我不知道是否可以使用Openiddict向令牌添加声明

索赔转换


事实上,在我发现这个方法之前,我使用了
HttpContext.Items
来存储额外的声明,它对我很有效。但我认为更好的方法是使用
声明转换
,它适合您的情况

有两种方法可以实现它:
首先,在自定义
SignInManager
中重写
CreateUserPrincipalSync
方法:

public override异步任务CreateUserPrincipalAsync(ApplicationAdmin用户)
{
var principal=await base.CreateUserPrincipalAsync(用户);
//如果需要,请使用this.UserManager
var identity=(ClaimsIdentity)principal.identity;
identity.AddClaim(新索赔(“MyClaimType”、“MyClaimValue”);
返还本金;
}
第二种方法是重写自定义
UserClaimsPrincipalFactory
CreateAsync
方法:

public override async Task CreateAsync(ApplicationUser用户)
{
var principal=await base.CreateAsync(用户);
var identity=(ClaimsIdentity)principal.identity;
identity.AddClaim(新索赔(“MyClaimType”、“MyClaimValue”);
返还本金;
}
这基本上是一样的,因为
SignInManager
中的
base.createUserPrincipalSync
方法调用
this.UserClaimsPrincipalFactory()
内部

不要忘记将自定义实现添加到服务中:
或者

public void配置服务(IServiceCollection服务)
{
...
services.AddSignInManager();
}

public void配置服务(IServiceCollection服务)
{
...
services.addScope();
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context) 
{
    var userManager= context.Context.RequestServices.GetRequiredService<UserManager>();
    //
}