我正在尝试为此用例实施授权:
我正在试用 Keycloak 和它的资源服务器。出于测试目的并了解这些范围和权限以及内容,我创建了测试客户端
weather-api
和一个资源 Weather
与 url /weatherforecast
.
然后我有范围
weather:read
和策略,每个具有角色weatherer
的用户都可以阅读该资源。
现在,当我尝试评估具有该角色的用户时,我得到
PERMIT
:
另一个没有这个角色的用户被拒绝。
所以我想我的政策和权限设置正确。
当我尝试从我的服务中使用它禁用用户管理访问时,我也获得了许可。
但是当我启用
user-managed-access
时,它失败了。
我在调试日志中看到它获得了权限令牌:
{
...
"permissions": [
{
"scopes": [
"weather:read"
],
"rsid": "ae5ac493-b7dc-481e-9204-a664d1558a51"
}
],
...
}
但是接下来的消息是
Policy enforcement result for path [http://192.168.0.9:5001/weatherforecast] is : DENIED
我尝试调试 Keycloak 库,发现了一些我不太明白的东西。
在
KeycloakAdapterPolicyEnforcer
这部分代码:
@Override
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
AccessToken original = accessToken;
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims)) {
return true;
}
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade, claims);
if (accessToken == null) {
return false;
}
...
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
return null;
}
...
}
所以当 UserManagedAccess 不为 null 时,
requestAuthorizationToken
返回 null 然后它的行为就像用户未经授权 HTTP 401
.
我在这里错过了什么?为什么它只能在没有 UMA 的情况下工作?
我看过这些(app-authz-uma-photoz,devconf2019-authz)示例,但没有注意到我遗漏了什么。
除非他们实际上是从 Java 应用程序为用户创建一些资源,否则我不是。但我想如果我保护用户创建的资源或单个“预制”URL 应该无关紧要,对吧?它应该只取决于正确的权限,因为它们评估为
PERMIT
所以我不明白为什么这不起作用。
还有一个问题。在用户之间永远不会有任何共享的情况下,对于“用户可以访问他自己的,管理员可以访问所有内容”的情况,这个 UMA 事情是不是太过分了?我正在考虑一些更简单的方法,可以在不在 Keycloak 中创建用户资源的情况下工作,但我想不出任何东西,我相信我仍然需要将用户 ID 与一些资源 ID 连接起来才能工作。
让我们在调试或您的 Catalina 会话中检查您的 KeycloakSecurityContext,也许它将为 null 并返回 403。只需将 enforcer 配置添加到 spring boot 配置文件中,前缀为:keycloak 对于 KeycloakSecurityContext 的初始默认上下文,Spring boot 将能够加载 Enforcer从keycloak服务器配置。
Spring 的 Keycloak 适配器已于 2022 年初弃用。不要使用它。它甚至不兼容 Spring Boot 3.
我在这个问题的答案中详细介绍了配置资源服务器的替代解决方案:Use Keycloak Spring Adapter with Spring Boot 3,但对于高级访问控制的示例,我建议您参考我关于该主题的教程。
如果您绝对想使用授权服务,则必须使用
WebClient
、@FeignClient
或其他方式手动调用 REST 端点。
我不喜欢Keycloak授权服务,原因如下:
相反,如果您编写方法安全表达式,例如
@PreAtuhorize("hasAutority('ADMIN') or #weatherForecast.authorUsername == #auth.tokenAttributes['preferred_username']")
@GetMapping("/weatherforecast/{forecastId}")
public WeatherForecastDto getForecast(@PathVariable("forecastId") WeatherForecastEntity weatherForecast, JwtAuthenticationToken auth) {
...
}
然后:
JwtAuthenticationToken
实例编写单元测试,以断言访问控制的行为符合您的预期