在讨论问题之前,先简要介绍一下我正在开发的系统。我有一个单点登录 (SSO) 系统,其中身份提供商 (IDP) 具有用于用户管理的 API 端点。有一个管理客户端应用程序充当用户管理的前端。用户可以登录并使用Admin Client查看、添加、编辑和删除用户。
在该系统中,授权码流程用于登录并访问客户端及其操作。当用户执行用户管理操作时,管理客户端中的控制器将向 IDP 的 API 端点发送请求。例如,像加载管理客户端的主页一样简单,主页控制器调用一个方法,向 IDP 的 API 端点发出请求,该端点将返回一个 JSON 文件,该文件可以传回主页以显示在表中前端。
管理客户端中的主页控制器已受到策略的保护,该策略在允许用户使用之前检查用户的身份验证和角色,因此管理客户端向 IDP 的 API 端点发出的请求受到使用客户端凭据流的保护。
本系统使用OpenIddict进行身份验证和授权。
这一切在本地开发环境中都运行良好。然而,我们现在正尝试将此系统部署到实时服务器上以对其进行测试/演示,但我们在管理客户端向 IDP 的 API 端点发出的请求中遇到错误。部署应用程序后,用户可以正常登录管理客户端,但无法加载主页,因为对 IDP API 端点的请求返回 401 未经授权的响应。
查看日志,问题似乎与令牌的受众价值有关:
The authentication demand was rejected because the token had no valid audience.
实时系统生成的令牌内容如下所示(通过 jwt.io 解码后):
{
"iss": "https://company.solutions/SSO_IDP",
"exp": 1729258266,
"iat": 1729254666,
"aud": "https://company.solutions/SSO_IDP",
"jti": "2a5427c7-b155-496d-8df8-0191649ad580",
"sub": "adminclient",
"name": "adminclient",
"oi_prst": "adminclient",
"client_id": "adminclient",
"oi_tkn_id": "f0ae2cd7-aa03-4d3a-89ea-fbe2decf5b24"
}
本地系统生成的token内容如下:
{
"iss": "https://localhost:7007/",
"exp": 1729262935,
"iat": 1729259335,
"aud": "https://localhost:7007/",
"jti": "65f8902a-99fb-4f1b-84e4-ef1422fa9b7c",
"sub": "adminclient",
"name": "adminclient",
"oi_prst": "adminclient",
"client_id": "adminclient",
"oi_tkn_id": "52352ecf-d942-4e13-fb69-5e15d7ccd956"
}
受众的唯一区别是我们的实时系统在子页面上运行(因此 /SSO_IDP),并且本地主机发行者和受众在末尾有一个“/”,而实时系统没有(这导致之前将 IDP 连接到管理客户端时出现问题)。
它获取此交换的发行者 URL 和受众的方式是通过 appsettings.json 中设置的值。然后在注册客户端时设置客户端的发行者等地方使用该值:
options.AddRegistration(new OpenIddictClientRegistration
{
ClientId = clientDetails.GetSection("ClientId").Value?.ToString(),
ClientSecret = clientDetails.GetSection("ClientSecret").Value?.ToString(),
Issuer = new Uri(clientDetails.GetSection("IssuerUrl").Value?.ToString(), UriKind.Absolute),
// Other options go here...
});
在IDP中设置受众时:
.AddValidation(options =>
{
options.AddAudiences(new Uri(configuration["AllowedDomains:IssuerUrl"]).GetLeftPart(UriPartial.Authority) + "/");
});
以及在 IDP 的交换端点中设置令牌的受众。
我的问题是:
有谁知道这里可能出了什么问题,以及为什么实时应用程序中发送的观众在本地环境中工作时无效?
有更好的方法来设置这些值吗?或者更重要的是,推荐的做法是什么?
是否有更好的方法来测试/调查这个问题,以便我可以更好地解决这个问题?
对于这么长的帖子,我深表歉意,但我感谢您提供的任何帮助。预先感谢您。
这是一个常见问题。我具体不了解Keycloak,但在一些类似的系统中,颁发者值取决于发出身份验证请求时应用程序的来源。
我确信您可以以某种方式将发行者硬编码为静态。在我使用的 IdentityServer 中,我必须对发行者进行硬编码才能使其正常工作。
核心问题是,根据您的部署方式,当用户发出身份验证请求时,问题是一个值,但当客户端应用程序将授权代码交换为实际令牌时,问题是一个不同的值。
参见https://keycloak.discourse.group/t/set-iss-in-jwt-to-custom-value-hardcoded-okay/21687