【问题标题】:IdentityServer4 Net Core 2 not calling custom iProfileServiceIdentityServer4 Net Core 2 不调用自定义 iProfileService
【发布时间】:2018-06-25 19:16:19
【问题描述】:

我已将我的 Identity Server 项目升级到 Net Core 2,但现在我无法获取要调用的 iProfileService 对象以添加自定义用户声明。它在 Net Core 1 中确实有效。

Startup.cs ConfigureServices 函数

            // Add application services.
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
        services.AddTransient<IProfileService, M25ProfileService>();

        //Load certificate
        var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "m25id-cert.pfx"), "mypassword");

        services.AddIdentityServer()
            .AddSigningCredential(cert)
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(connectionString,
                        sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(connectionString,
                        sql => sql.MigrationsAssembly(migrationsAssembly));
                //options.EnableTokenCleanup = true;
                //options.TokenCleanupInterval = 30;
            })
            .AddProfileService<M25ProfileService>()
            .AddAspNetIdentity<ApplicationUser>();

M25ProfileService.cs

    public class M25ProfileService : IProfileService
{
    public M25ProfileService(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var user = _userManager.GetUserAsync(context.Subject).Result;

        var claims = new List<Claim>
        {
            new Claim(JwtClaimTypes.GivenName, user.FirstName),
            new Claim(JwtClaimTypes.FamilyName, user.LastName),
            new Claim(IdentityServerConstants.StandardScopes.Email, user.Email),
            new Claim("uid", user.Id),
            new Claim(JwtClaimTypes.ZoneInfo, user.TimeZone)
        };
        if (user.UserType != null) claims.Add(new Claim("mut", ((int)user.UserType).ToString()));
        context.IssuedClaims.AddRange(claims);
        return Task.FromResult(0);

    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        var user = _userManager.GetUserAsync(context.Subject).Result;
        context.IsActive = user != null;
        return Task.FromResult(0);
    }
}

}

Config.cs

    public class Config
{
    // try adding claims to id token
    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        var m25Profile = new IdentityResource(
            "m25.profile", 
            "m25 Profile", 
            new[]
            {
                ClaimTypes.Name,
                ClaimTypes.Email,
                IdentityServerConstants.StandardScopes.OpenId,
                JwtClaimTypes.GivenName,
                JwtClaimTypes.FamilyName,
                IdentityServerConstants.StandardScopes.Email,
                "uid",
                JwtClaimTypes.ZoneInfo
            }
        );

        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
            new IdentityResources.Email(),
            m25Profile
        };
    }

    public static IEnumerable<ApiResource> GetApiResources()
    {
        //Try adding claims to access token
        return new List<ApiResource>
        {
            new ApiResource(
                "m25api",
                "message25 API",
                new[]
                {
                    ClaimTypes.Name,
                    ClaimTypes.Email,
                    IdentityServerConstants.StandardScopes.OpenId,
                    JwtClaimTypes.GivenName,
                    JwtClaimTypes.FamilyName,
                    IdentityServerConstants.StandardScopes.Email,
                    "uid",
                    JwtClaimTypes.ZoneInfo
                }
            )
        };
    }

    public static IEnumerable<Client> GetClients()
    {
        // client credentials client
        return new List<Client>
        {
            new Client
            {
                ClientId = "client",
                ClientName = "Client",
                AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },
                AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    "m25api"
                }
            },

            // Local Development Client
            new Client
            {
                ClientId = "m25AppDev",
                ClientName = "me25",
                AllowedGrantTypes = GrantTypes.Implicit,
                AllowAccessTokensViaBrowser = true,
                RequireConsent = false,

                RedirectUris = { "http://localhost:4200/authorize.html" },
                PostLogoutRedirectUris = { "http://localhost:4200/index.html" },
                AllowedCorsOrigins = { "http://localhost:4200" },

                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    JwtClaimTypes.GivenName,
                    "mut",
                    "m25api"
                },
                AllowOfflineAccess = true,

                IdentityTokenLifetime = 300,
                AccessTokenLifetime = 86400
            }
        };
    }
}

我尝试的第一件事就是让身份服务器允许我登录并显示类似于 id4 示例的用户声明。当我登录时,列出了标准声明,但没有列出任何自定义声明。我在 M25ProfileService 类中设置了断点,但它们永远不会被击中。似乎 ID4 从未使用过客户 ProfileService 类,但我的 startup.cs 中确实有它。

我也尝试过我的测试 JS 客户端并得到相同的结果。这是来自我的 JS 客户端的 sn-p:

var config = {
    authority: "http://localhost:5000",
    client_id: "m25AppDev",
    redirect_uri: "http://localhost:4200/authorize.html",
    response_type: "id_token token",
    scope:"openid profile m25api",
    post_logout_redirect_uri : "http://localhost:4200/index.html"
};
var mgr = new Oidc.UserManager(config);

mgr.getUser().then(function (user) {
    if (user) {
        log("User logged in", user.profile);
        document.getElementById("accessToken").innerHTML = "Bearer " + user.access_token + "\r\n";
    }
    else {
        log("User not logged in");
    }
});

function login() {
    mgr.signinRedirect();
}

目前,我不确定该尝试什么。我想如果我将声明添加到 id 令牌(据我了解的 GetIdentityResources() 函数)甚至访问令牌(据我了解的 GetApiResources() 函数),我会看到声明,但似乎没有任何效果。请帮忙!提前致谢!

此外,我曾经能够从我的客户端以及在日志后呈现的 Identity Server 自己的索引页面获取自定义声明

【问题讨论】:

  • 您在调用 UserInfo 端点吗?可以显示客户端配置吗?
  • 我刚刚从 JS 客户端添加了客户端配置代码。但是,如果我直接访问 ID 服务器,我什至无法从 ID 服务器的索引页面获取它,我在登录后呈现声明。
  • 对我有用的是清除 cookie。

标签: profile asp.net-core-2.0 identityserver4


【解决方案1】:

更改这些代码行的顺序:

.AddProfileService<M25ProfileService>()
.AddAspNetIdentity<ApplicationUser>();

如果覆盖另一个。

【讨论】:

  • 我最初更改了订单,但认为这是问题所在。我只是忘记改回来了。感谢您指出了这一点。不幸的是,这仍然不能解决问题。
  • 您需要将其注册为临时服务吗?删除该行并重试。您正在向 Identity Server 注册您的 IProfileService 实现。
  • 嘿 Derek,我以前试过,但没有帮助。我在文档中看到它注册了瞬态但没有注册它。这两种方式似乎都没有什么不同。
【解决方案2】:

我想通了。感谢 GitHub 上的 some code,我能够弄清楚我错过了什么。我只需将这两行添加到 config.cs 中每个客户端的配置中,一切都完美无缺!

AlwaysSendClientClaims = true,
AlwaysIncludeUserClaimsInIdToken = true

这适用于远程客户端。但是,当我在 ID 服务器本身登录(而不是从客户端)时,我仍然无法让它工作。目前这没什么大不了的,但将来可能会是这样。如果/当我弄清楚那部分时,我会尽量记住更新我的答案。同时,我希望这对其他人有所帮助。

【讨论】:

  • 使用 AlwaysIncludeUserClaimsInIdToken 是否意味着声明包含在标题中或作为正文?具有 100 个声明的应用程序可能会超过标头大小,并且请求被拒绝。还是我错过了什么?
【解决方案3】:

除了上面的答案(除了问题中显示的 Startup.cs 已经包含相关的代码行之外)我想添加另一个非常简单的原因来解释为什么 Profile Service 可能不被称为:

别忘了向依赖注入容器注册服务!

因为只有.AddProfileService&lt;ProfileService&gt;() 是不够的。

您还需要:

services.AddScoped<IProfileService, ProfileService>();

或者:

services.AddTransient<IProfileService, ProfileService>();

【讨论】:

  • 对我来说,有必要添加“services.AddTransient();”添加“AddIdentityServer”后
  • 这个答案是正确的。 IProfileService 必须通过 DI 注册,没有它在我这边就无法工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-20
  • 2017-04-20
  • 2018-09-25
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多