首页 > 解决方案 > 带有 PKCE 的 OpenID Connect 代码流仅返回子声明

问题描述

我正在使用这个带有 PKCE 的 OpenID Connect 代码流的 Angular Lib来创建一个带有 openid 连接身份验证的 SPA。此外,我正在使用身份服务器 4

SPA 中的 OIDC 配置

{
"stsServer": "http://localhost:5000",
"redirect_url": "http://localhost:4200",
"client_id": "angularclient",
"response_type": "code",
"scope": "openid profile email address phone api1",
"post_logout_redirect_uri": "http://localhost:4200",
"start_checksession": true,
"silent_renew": true,
"silent_renew_url": "http://localhost:4200/silent-renew.html",
"post_login_route": "/home",
"forbidden_route": "/forbidden",
"unauthorized_route": "/unauthorized",
"log_console_warning_active": true,
"log_console_debug_active": true,
"max_id_token_iat_offset_allowed_in_seconds": 10
}

身份服务器的 OIDC 配置

new Client
{
    ClientName = "angularclient",
    ClientId = "angularclient",
    AccessTokenType = AccessTokenType.Reference,
    // RequireConsent = false,
    AccessTokenLifetime = 3600,// 330 seconds, default 60 minutes
    IdentityTokenLifetime = 3600,

    RequireClientSecret = false,
    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,

    AllowAccessTokensViaBrowser = true,
    RedirectUris = new List<string>
    {
        "http://localhost:4200",
        "http://localhost:4200/callback.html",
        "http://localhost:4200/silent-renew.html"
    },
    PostLogoutRedirectUris = new List<string>
    {
        "http://localhost:4200/",
        "http://localhost:4200"
    },
    AllowedCorsOrigins = new List<string>
    {
        "http://localhost:4200"
    },
    AllowedScopes = new List<string>
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        IdentityServerConstants.StandardScopes.Address,
        IdentityServerConstants.StandardScopes.Phone,
        "api1"
    }
}

当我访问 userinfo_endpoint 时,仅返回 sub 声明。

{ "sub": "818727" }

我的配置中缺少什么?我是否必须配置从 userinfo_endpoint 返回的声明?

标签: angular.net-coreidentityserver4openid-connect

解决方案


使用 CustomProfileService 会返回声明。感谢@Randy 和@Shantanu 的提示。

public class CustomProfileService : IProfileService
{
    private readonly TestUserStore _users;

    public CustomProfileService(TestUserStore users = null)
    {
        _users = users ?? new TestUserStore(TestUsers.Users);
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var sub = context.Subject.FindFirst("sub").Value;
        if (sub != null)
        {
            var user = _users.FindBySubjectId(sub);
            var claimsPrincipal = await GetClaimsAsync(user);
            var claims = claimsPrincipal.Claims.ToList();

            if (context.RequestedClaimTypes != null && context.RequestedClaimTypes.Any())
            {
                claims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
            }

            context.IssuedClaims = claims;
        }
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
    }

    private async Task<ClaimsPrincipal> GetClaimsAsync(TestUser user)
    {
        if (user == null)
        {
            throw new ArgumentNullException(nameof(user));
        }

        return await Task.Factory.StartNew(() =>
        {
            var claimsIdentity = new ClaimsIdentity();
            claimsIdentity.AddClaims(user.Claims);

            return new ClaimsPrincipal(claimsIdentity);
        });
    }
}

启动.cs

builder.Services.AddTransient<IProfileService, CustomProfileService>();

推荐阅读