Identity Server 4使用IConfiguration创建客户端

3

我将我的身份验证服务器的客户端存储在一个appsettings.json文件中:

"ClientSettings":  [
{
  "ClientId": "TestClient1",
  "RedirectUris": [ "http://localhost:5002/signin-oidc" ],
  "PostLogoutRedirectUris": [ "http://localhost:5002/signout-callback-oidc" ],
  "AllowedGrantTypes": [ "hybrid" ],
  "AllowedScopes": [ "openid","profile","email" ],
  "RequireConsent": "false",
  "Enabled": "true",
  "ClientSecrets": [
    {
      "Description": "This is the client sceret description.",
      "Value": "password123"
    }
  ]
}
],

在我的ConfigureServices方法中,我设置了依赖注入。

services.Configure<List<Client>>(config.GetSection("ClientSettings"));

我的IClientStore通过依赖注入获取客户端列表。当然,我需要对客户端密钥进行哈希处理。为了保持这个问题的简单性,我编写了以下代码,假设我只有一个客户端和一个客户端密钥。

public ClientConfigFileStore(IOptions<List<Client>> options)
{
    var jsonClient = options.Value[0];
    Client client = new Client()
    {
        ClientId = jsonClient.ClientId,
        RedirectUris = jsonClient.RedirectUris,
        PostLogoutRedirectUris = jsonClient.PostLogoutRedirectUris,
        AllowedGrantTypes = jsonClient.AllowedGrantTypes,
        AllowedScopes = jsonClient.AllowedScopes,
        RequireConsent = jsonClient.RequireConsent,
        Enabled = jsonClient.Enabled,
    };//Works
    Client client = jsonClient;//Does not work

    client.ClientSecrets = new List<Secret>()
    {
        new Secret(jsonClient.ClientSecrets.First().Value.Sha256())
    };
    clients = new List<Client>() { client };
}

我需要创建一个新的Client实例,但是使用依赖注入创建的实例无法工作。在用户在身份服务器输入凭据后,重定向回客户端失败,出现错误Client secret validation failed for the client: TestClient1

为什么需要创建一个新实例?是否有更优雅的方式从appsettings.json文件中加载客户端信息?


为什么要从那个文件中加载它们?为什么不给它自己的文件? - Linda Lawton - DaImTo
1
我也可以做到,并且会更有条理。但这并不能解决问题吧? - jasdefer
为什么不直接使用AddInMemoryClients?我猜我不明白你为什么要这样做,你到底想做什么? - Linda Lawton - DaImTo
我想要一个简单的方法来调整客户端设置。当使用“AddInMemoryClients”进行设置调整时,需要发布身份验证服务器的新版本。 - jasdefer
这就是它的工作原理。我认为你不能在内存中即时添加新客户端。如果你想这样做,应该将它们放在数据库中。我会去查看代码,看看是否有一种方法可以即时添加内存客户端。 - Linda Lawton - DaImTo
好的,一开始我并不想硬编码客户端密钥。所以我使用了appsettings.json文件来实现这个目的。然后我想,为什么不把所有客户端特定的设置都移到这个(或者另一个)文件中呢?现在我很好奇,为什么需要创建一个新实例。 - jasdefer
2个回答

0

我不确定我完全理解你试图做什么或为什么要这样做。主要是我不确定你为什么想像这样在 DI 中加载它们。你应该考虑使用内存客户端。

startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        // configure identity server with in-memory stores, keys, clients and scopes
        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients());
    }

config.cs

public class Config
{
    // scopes define the API resources in your system
    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource("api1", "My API")
        };
    }

    // clients want to access resources (aka scopes)
    public static IEnumerable<Client> GetClients()
    {
        // client credentials client
        return new List<Client>
        {
            new Client
            {
                ClientId = "client",
                AllowedGrantTypes = GrantTypes.ClientCredentials,

                ClientSecrets = 
                {
                    new Secret("secret".Sha256())
                },
                AllowedScopes = { "api1" }
            }
        };
    }
}

来自快速入门IdentityServer的代码


你对于内存方法是正确的。我编辑了你的答案以适应我的需求,以防其他人有类似的问题。我更喜欢从*.json文件中加载客户端,而不是硬编码它们。这也可以从代码库中删除机密信息。尽管我仍然不知道为什么这种转换(或创建新实例并复制)有效,而另一种方法则无效。 - jasdefer

0

将您的客户端密钥部分更改为以下内容:

"ClientSecrets": [
      {
        "Value": "<Sha256 hash of secret>",
        "Type": "SharedSecret"
      }
 ],

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接