如何从 IdentityServer4 中的 .net Core web API 访问身份提供者 (idp) 声明?

How to access identity provider (idp) claim from .net Core web API in IdentityServer4?

在我受 IdentityServer4 保护的 .Net Core web API 中,我需要决定哪个身份提供者(例如,Google、Windows 或本地)对用户进行身份验证。到目前为止,我不确定该怎么做。

如果我在控制器中搜索 access_token 的 idp 声明,如下所示,我可以正确地看到声明值

var accessToken = await HttpContext.GetTokenAsync("access_token");
var token = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
var claim = token.Claims.First(c => c.Type == "idp").Value;

但是如果我尝试在 API 中的非控制器 class 中使用 AuthorizationHandlerContext 找到它,如下面的代码所示,它不存在

    var identity = context.User.Identity as ClaimsIdentity;
    if (identity != null)
    {
        IEnumerable<Claim> claims = identity.Claims;
        // var v = identity.FindFirst("idp").Value;
    }

看起来 idp 确实在令牌中,只是无法从需要它的非控制器 class 访问它。如何从 API 中的非控制器 class 获取 idp?

更新 - 1

这是我的 API

中的 ConfigureService
public void ConfigureServices(IServiceCollection services)
{
    IdentityModelEventSource.ShowPII = true; // test only
    services.AddControllers();

    services.AddControllers()
         .AddNewtonsoftJson(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );          
    });

    services.Configure<QLHostOptions>(Configuration.GetSection(QLHostOptions.Host));

    services.AddAuthentication("Bearer").AddJwtBearer("Bearer", options =>
    {
        options.Authority = Configuration.GetSection(QLHostOptions.Host).Get<QLHostOptions>().IdentityGateway;
        options.SaveToken = true; 

        // test only
        options.RequireHttpsMetadata = false;

        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false
        };
    }).AddOpenIdConnect(options =>
    {
        options.ClaimActions.Remove("aud");
    });

    services.AddTransient<IAuthorizationPolicyProvider, QLPolicyProvider>();
    services.AddTransient<IAuthorizationHandler, QLPermissionHandler>();

    services.AddTransient<gRPCServiceHelper>();

}

UPDATE-2

按照 Tory 的建议,将 ...Remove("idp") 更改为 AddJwtBearer 内部,但它没有接受(见下面的屏幕截图):

这是来自 API

的访问令牌
"eyJhbGciOiJSUzI1NiIsImtpZCI6IjBFM0Y2MkRGMTdFQUExQURFRTc1NDQzQzQ0M0YxRkU2IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2NDAwMzExMDcsImV4cCI6MTY0MDAzNDcwNywiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NjAwNSIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjYwMDUvcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoibXZjIiwic3ViIjoiZGM0YWI1OGMtNGVjMC00ZTAyLWIxM2YtYzEyYzk1MzJlNzcyIiwiYXV0aF90aW1lIjoxNjQwMDMxMTA2LCJpZHAiOiJHb29nbGUiLCJBc3BOZXQuSWRlbnRpdHkuU2VjdXJpdHlTdGFtcCI6IjJEQ0hXNVRER1E3NDNSUEpOWE43SVJIWlRIVllIUTRJIiwibmFtZSI6IkxpZmVuZyBYdSIsImVtYWlsIjoibGlmZW5neHUyNkBnbWFpbC5jb20iLCJyb2xlIjoiUUxBZG1pbiIsInByZWZlcnJlZF91c2VybmFtZSI6IjM1ZGJkMmY2LTlmNDUtNDJhYy04M2EzLTgzZmUyMTFjNTNiNSIsIklzRW5hYmxlZCI6IlRydWUiLCJRaWNMaW5rVUlEIjoiIiwianRpIjoiQzE3Qjc2QzQ0NjA4MzkxMDBENEExMEM4Q0YwQzA1NDEiLCJzaWQiOiIzMEY5NTA5NzQ3OUUxMzAyMUVBQTdDOTAzNzg4MDcxNiIsImlhdCI6MTY0MDAzMTEwNywic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsImVtYWlsIiwiUWljTGlua0NJRCIsIlFpY0xpbmtVSUQiLCJyb2xlcyIsIklzRW5hYmxlZCIsIkxpZmVuZ0FQSSIsIlFpY0xpbmtBUEkiLCJvZmZsaW5lX2FjY2VzcyJdLCJhbXIiOlsiZXh0ZXJuYWwiXX0.boZCqYImWfkE48X5UgFOAAz9bR6CH2cwAYHGd4Ykg0vDH9qnYdje5Zmqov4HpINsu_rt16zxAX_JCEn0hvdznXK2NQyZSBGsjF0tcMgtOY0__kAfhpOT-fORakiIjeMWIKG7tPEHCxSib0wNuMNw6i3o1giAnPt0ch2DH0fBtaEYkq4MRKMCteFuqbX0cogXIuMewNywMvrHv4_MixhMy3L8_xIwFvTZ67jhUn4Fd5X58-jc-RPNudcP95XIjzHm9OzWfgegV1IAKjsv98XEYX1pUxm-nrOMgYWxEJSyxEpp0L_9RzKTr_LZ-ep-x5QRvVewgiozJV3mse0pHgTjbw"

默认情况下,令牌中的许多内部声明已从 User ClaimsPrinicpal 声明中删除。

如果你想对你的用户进行特定的声明,你可以在客户端中使用:

}).AddOpenIDConnect(options =>
{
    //Will result in that the aud claim is not removed.
    options.ClaimActions.Remove("idp");
...

其次,一些声明被重命名,如果你想禁用重命名,你可以添加:

// By default, Microsoft has some legacy claim mapping that converts
// standard JWT claims into proprietary ones. This removes those mappings.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();

对于 API,您无需执行任何特殊操作即可获得 idp 声明。我只是 运行 在 .NET 5 中使用此设置进行测试:

public void ConfigureServices(IServiceCollection services)
{

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMyJwtBearer(opt =>
    {
        opt.IncludeErrorDetails = true;
        opt.MapInboundClaims = false;
        opt.TokenValidationParameters.RoleClaimType = "role";
        opt.TokenValidationParameters.NameClaimType = "name";
        opt.Audience = "paymentapi";
        opt.Authority = "https://localhost:6001";
    });

    services.AddControllers();
}

我确实在 .NET 5 上对其进行了测试,如果我有此访问令牌:

{
  "nbf": 1640033816,
  "exp": 1640037416,
  "iss": "https://localhost:6001",
  "aud": "paymentapi",
  "client_id": "clientcredentialclient",
  "managment": "yes",
  "email": "tore@tn-data.se",
  "name": "tore nestenius",
  "idp": "Google",
  "role": [
    "admin",
    "developer",
    "support"
  ],
  "website": "https://www.tn-data.se",
  "jti": "5DC46A29372031F0AA6F7B62B5FDCCD6",
  "iat": 1640033816,
  "scope": [
    "payment"
  ]
}

然后我的 API 控制器中的用户包含 idp 声明: