我看过这两篇文章为这个问题提供了解决方案,但是它们没有提供关于如何为像我这样的非Java开发人员做的足够详细的信息:
Keycloak add extra claims from database / external source
How to register a custom ProtocolMapper in Keycloak?
这里是他们的解决方案的概述,如果他们提供了更多详细信息,可能会帮助其他人。
期望的过程 from 1st link
- 用户登录
- 调用我的自定义协议映射器,在这里我覆盖了transformAccessToken方法
- 在这里,我将协议映射器所在的客户端作为服务登录到keycloak中。在这里别忘了使用其他客户端ID 而不是您要为其构建协议映射器的那个,您将输入 否则无休止的递归。
- 我将访问令牌放入协议映射器,并调用应用程序的其余端点以获取额外的声明,这是 安全的。
- 获取端点返回的信息并将其添加为额外声明
实现目标的步骤 from 2nd link
实现ProtocolMapper接口并添加文件 “ META-INF / services / org.keycloak.protocol.ProtocolMapper” 包含对该类的引用。
此时,Keycloak可以识别新的实现。你呢 应该可以通过管理控制台进行配置。
要向令牌添加一些数据,请添加以下接口
org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper
并根据界面实现方法
然后将文件“ META-INF / jboss-deployment-structure.xml ”与 以下内容
<?xml version="1.0" encoding="UTF-8"?> <jboss-deployment-structure> <deployment> <dependencies> <module name="org.keycloak.keycloak-services"/> </dependencies> </deployment> </jboss-deployment-structure>
完成所有这些操作后,将调用自定义transformAccessToken()方法 每次对URL的请求 http://:/ auth / realms / testrealm / protocol / openid-connect / token
阅读本文后,我有几个问题:
谢谢大家的时间。 如果我想念他们的答案,请告诉我。
编辑:
我开始提供赏金,希望有人能够给我详细的步骤,说明如何从Keycloak 3.4.3中添加数据库的额外声明(对于非Java开发人员而言足够详细)
编辑2 此处描述的方法可以解决问题,但缺少细节。 Keycloak create a custom identity provider mapper
答案 0 :(得分:10)
希望本逐步指南对您有帮助
我正在使用Keycloak 4.5.0-因为我已经安装了这个较新的版本-但我应该不会有太大的不同。我在示例中实现了OIDCProtocolMapper
。
仅作总结-为其他内容提供快速概述-每个步骤将在以后更详细地描述
您将基于以下内容实现CustomProtocolMapper类
AbstractOIDCProtocolMapper
META-INF / services文件与
名称org.keycloak.protocol.ProtocolMapper
必须可用,并且
包含您的映射器的名称
jboss-deployment-structure.xml
必须可以使用
内置于类中的keycloak
Jar文件部署在
/opt/jboss/keycloak/standalone/deployments/
现在确定更多细节:-)
我将您的Maven pom.xml
(pom)上传给您-只需将其导入您的IDE中,所有依赖项都应自动加载。依赖关系仅为provided
,以后将在运行时直接从keycloak中使用
相关的是keycloak.version
属性-当前所有密钥库相关性都已加载到版本4.5.0.Final
现在,我创建了一个名为CustomOIDCProtocolMapper
的自定义协议映射器类。查找“完整”代码here
它应该扩展AbstractOIDCProtocolMapper
并需要实现所有抽象方法。也许您想拥有一个SAML协议映射器,那么它是另一个基类(AbstractSAMLProtocolMapper
)
一种相关的方法是transformAccessToken
-在这里,我为AccessToken设置了另一个Claim。您需要在这里使用逻辑,但是,是的-取决于您的数据库等;-)
服务文件对于Keycloak 重要很重要,以查找您的自定义实现
在org.keycloak.protocol.ProtocolMapper
\src\main\resources\META-INF\services\
的文件
在此文件中,您写入自定义提供程序的名称-因此keycloak知道该类可用作协议映射器
在我的示例中,文件内容仅为一行
com.stackoverflow.keycloak.custom.CustomOIDCProtocolMapper
在自定义映射器中,您将使用keycloak中的文件。为了使用它们,我们需要通知jboss这个依赖关系。
因此,请在jboss-deployment-structure.xml
内创建文件\src\main\resources\META-INF\
内容:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-services" />
</dependencies>
</deployment>
</jboss-deployment-structure>
构建扩展文件(mvn clean package
的jar文件-将jar
放在/opt/jboss/keycloak/standalone/deployments/
中,然后重新启动密钥斗篷
在日志文件中,您应该看到其部署时间以及(希望没有)错误消息
现在您可以使用您的映射器-在我的示例中,我可以在keycloak admin ui中创建一个映射器,然后从下拉列表中选择Stackoverflow Custom Protocol Mapper
仅作为信息-密钥斗篷尚未完全正式支持-因此界面可能会在更高版本中更改
我希望它是可以理解的,并且您将能够成功实现自己的映射器
编辑: 导出的日食文件结构zip
答案 1 :(得分:1)
我正在使用自定义协议映射器 1 发送已认证 2 GraphQL查询< / strong> 3 到外部系统,并将JSON响应数据放入用户的访问令牌(JWT)中。当前它与Keycloak 10一起运行。
==>您可以在this repository中找到完整的代码。
正如其他人所指出的,您的项目至少需要3个文件。
AbstractOIDCProtocolMapper
及其方法setClaim
(以及其他方法)的Java类。jboss-deployment-structure.xml
文件,其中包含部署依赖项。org.keycloak.protocol.ProtocolMapper
文件,其中包含自定义协议映射器的全名。这是文件夹结构:
$ tree src/ -A
src/
└── main
├── java
│ └── com
│ └── thohol
│ └── keycloak
│ └── JsonGraphQlRemoteClaim.java
└── resources
└── META-INF
├── jboss-deployment-structure.xml
└── services
└── org.keycloak.protocol.ProtocolMapper
如果远程端点需要身份验证,我们可以从Keycloak获取访问令牌。完整的流程如下所示(尤其是步骤3-6):
login-client
。login-client
被配置为使用“自定义协议映射器”,因此其代码将在处理用户的身份验证请求时执行。remote-claims-client
(客户端ID +机密)针对第二个Keycloak客户端(例如client_credentials
)发出请求。remote-claims-client
的访问令牌。Authorization: Bearer <access token>
标头已添加到请求标头中。remote-claims-client
铸造(“写”)令牌。步骤3/4可以用Java中的简单HTTP POST请求实现(省略错误处理!):
// Call remote service
HttpClient httpClient = HttpClient.newHttpClient();
URIBuilder uriBuilder = new URIBuilder(keycloakAuthUrl);
URI uri = uriBuilder.build();
HttpRequest.Builder builder = HttpRequest.newBuilder().uri(uri);
String queryBody = "grant_type=client_credentials&client_id=remote-claims-client&client_secret=dfebc62a-e8d7-4ab3-9196-258ddb5684ab";
builder.POST(HttpRequest.BodyPublishers.ofString(queryBody));
// Build headers
builder.header(HttpHeaders.CONTENT_TYPE , MediaType.APPLICATION_FORM_URLENCODED);
// Call
HttpResponse<String> response = httpClient.send(builder.build(), HttpResponse.BodyHandlers.ofString());
// Process Response
JsonNode json = return new ObjectMapper().readTree(response.body());
String accessToken = json.findValue("access_token").asText();
GraphQL查询本质上是一个HTTP POST请求,带有一个body
之类的
{
"query": "query HeroName($episode: Episode) {
hero(episode: $episode) {
name
}
}",
"variables": {
"episode" : "JEDI"
}
}
可以像这样从Java发送(省略错误处理!):
HttpClient httpClient = HttpClient.newHttpClient();
URIBuilder uriBuilder = new URIBuilder(remoteUrl);
URI uri = uriBuilder.build();
HttpRequest.Builder builder = HttpRequest.newBuilder().uri(uri);
String queryBody = "{
\"query\": \"query HeroName($episode: Episode) {
hero(episode: $episode) {
name
}
}\",
\"variables\": {
\"episode\" : \"JEDI\"
}
}";
builder.POST(HttpRequest.BodyPublishers.ofString(queryBody));
// Build headers
builder.header(HttpHeaders.CONTENT_TYPE , MediaType.APPLICATION_JSON);
builder.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
// Call
HttpResponse<String> response = httpClient.send(builder.build(), HttpResponse.BodyHandlers.ofString());
// Process Response and add to token
JsonNode json = return new ObjectMapper().readTree(response.body());
clientSessionCtx.setAttribute("custom_claims", json);
我是链接存储库的所有者/作者。但是,我并不是从零开始,而是使用其他多个存储库作为基础/灵感。参见repo's README。