首页 > 解决方案 > 使用 Windows 身份验证的 IdentityServer4 委派 User.Identity.Name 为 null

问题描述

我有以下流程 Asp.Net Core App (App) 调用 Asp.Net Core Web API (API1) 又调用另一个 Asp.Net Web API (API2)

我正在使用带有 Windows 身份验证的 IdentityServer4 来验证我的用户,这是我的代码:

ApiResources 定义:

new ApiResource("api1", "api1", new List<string> {  JwtClaimTypes.Name, JwtClaimTypes.Email}),
new ApiResource("api2", "api2", new List<string> {  JwtClaimTypes.Name, JwtClaimTypes.Email})

客户定义

new Client
{
    ClientId = "app1",
    ClientName = "app1",
    ClientSecrets = { new Secret("app1".Sha256())},
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.OfflineAccess,
        IdentityServerConstants.StandardScopes.Email,
        "api1"
    },
    RedirectUris = { "https://localhost:44375/signin-oidc" },
    FrontChannelLogoutUri = "https://localhost:44375/signout-oidc",
    PostLogoutRedirectUris = { "https://localhost:44375/signout-callback-oidc" },

    AllowOfflineAccess = true,
    RequireConsent = false,
    AccessTokenLifetime = 5
},
new Client
{
    ClientId = "api1",
    ClientSecrets = { new Secret("api1".Sha256())},
    AllowedGrantTypes = {"delegation" },
    AllowedScopes = {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        "api2"}
}

API1 中的委托代码

public async Task<string> DelegateAsync(string userToken)
{
    var client = new HttpClient();
    var disco = await client.GetDiscoveryDocumentAsync("https://localhost:44382/");
    if (disco.IsError) throw new Exception(disco.Error);

    var tokenResponse = await client.RequestTokenAsync(new TokenRequest()
    {
        Address = disco.TokenEndpoint,
        GrantType = "delegation",
        ClientId = "api1",
        ClientSecret = "api1",
        Parameters =
        {
            {"scope" , "api2 email profile openid" },
            {"token", userToken }
        }
    });

    if (tokenResponse.IsError)
    {
        throw new Exception(tokenResponse.Error);
    }


    _logger.LogInformation($"new: {tokenResponse.AccessToken}");

    return tokenResponse.AccessToken;
}

IdentityServer4 委托授权验证器:

public class DelegationGrantValidator : IExtensionGrantValidator
{
    private readonly ITokenValidator _validator;

    public DelegationGrantValidator(ITokenValidator validator)
    {
        _validator = validator;
    }

    public string GrantType => "delegation";

    public async Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        var userToken = context.Request.Raw.Get("token");

        if (string.IsNullOrEmpty(userToken))
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return;
        }

        var result = await _validator.ValidateAccessTokenAsync(userToken);
        if (result.IsError)
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
            return;
        }

        // get user's identity
        var sub = result.Claims.FirstOrDefault(c => c.Type == "sub").Value;

        context.Result = new GrantValidationResult(sub, GrantType);
        return;
    }
}

在 API1User.Identity.Name = "Domain\UserName" 但在 API2User.Identity.Name = null

我应该解决这个问题吗?

PS:如果我从 API2 调用 IdentityServer UserInfo 端点,我将得到预期的 UserName

标签: identityserver4windows-authenticationasp.net-core-3.1

解决方案


经过大量搜索,我终于找到了答案。

我已经按照本文中描述的 Rory Braybrook 进行了操作,现在一切正常


推荐阅读