如何通过Java代码实现基于Keycloak的Argo Workflows SSO认证?
Keycloak认证Argo Workflows服务调用的Java解决方案
错误原因
token not valid for running mode 是因为你传递的用户登录token,其受众(aud字段)仅匹配Argo UI的客户端ID,但Argo Server在服务调用模式下,要求token的受众必须是服务端专用的客户端ID,或者你的Argo配置未允许用户token用于服务调用。
前置配置调整
- 在Keycloak中新增一个Confidential类型的客户端(命名如
argo-server-service):- 启用
Client Credentials授权类型 - 给该客户端分配Argo所需的权限角色(比如
admin、workflow-submit等)
- 启用
- 更新Argo Server的ConfigMap:
- 若使用服务专用token,设置
server.sso.clientId为这个新客户端ID - 若要支持用户上下文token,添加
server.sso.audiences配置,同时包含UI客户端ID和服务端客户端ID:server.sso.audiences: "argo-ui,argo-server-service"
- 若使用服务专用token,设置
Java代码实现
方式1:Client Credentials模式(服务间调用推荐,无用户上下文)
这种方式用服务端客户端凭证从Keycloak获取专用token,适合后台服务直接调用Argo API:
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class ArgoKeycloakAuth { // 获取服务专用token public static String getArgoServiceToken() throws Exception { String keycloakTokenUrl = "https://your-keycloak-domain/auth/realms/your-realm/protocol/openid-connect/token"; String clientId = "argo-server-service"; String clientSecret = "your-client-secret"; HttpClient client = HttpClients.createDefault(); HttpPost tokenPost = new HttpPost(keycloakTokenUrl); tokenPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); // 构建请求体 String requestBody = String.format( "grant_type=client_credentials&client_id=%s&client_secret=%s", clientId, clientSecret ); tokenPost.setEntity(new StringEntity(requestBody)); HttpResponse response = client.execute(tokenPost); String responseStr = EntityUtils.toString(response.getEntity()); // 解析access_token ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(responseStr); return jsonNode.get("access_token").asText(); } // 调用Argo Workflows API示例(提交Workflow) public static void submitArgoWorkflow(String argoServerUrl, String workflowJson) throws Exception { String serviceToken = getArgoServiceToken(); HttpClient client = HttpClients.createDefault(); HttpPost submitPost = new HttpPost(argoServerUrl + "/api/v1/workflows/default/submit"); // 设置认证头和内容类型 submitPost.setHeader("Authorization", "Bearer " + serviceToken); submitPost.setHeader("Content-Type", "application/json"); submitPost.setEntity(new StringEntity(workflowJson)); HttpResponse response = client.execute(submitPost); // 处理响应 System.out.println("API响应状态: " + response.getStatusLine()); System.out.println("响应内容: " + EntityUtils.toString(response.getEntity())); } public static void main(String[] args) throws Exception { // 替换为你的Workflow定义JSON和Argo Server地址 String workflowDef = "{\"workflow\": {\"apiVersion\": \"argoproj.io/v1alpha1\", \"kind\": \"Workflow\", ...}}"; submitArgoWorkflow("https://your-argo-server-url", workflowDef); } }
注意:代码依赖Apache HttpClient和Jackson Databind,Maven依赖如下:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.14</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency>
方式2:传递用户上下文token(需Argo配置支持)
如果需要携带用户身份调用Argo,确保用户token的aud字段包含Argo服务端客户端ID,或已在Argo ConfigMap中配置server.sso.audiences允许用户token,代码示例:
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; public class ArgoUserAuth { // 使用用户token调用Argo API public static void callArgoWithUserToken(String argoServerUrl, String userAccessToken, String workflowJson) throws Exception { HttpClient client = HttpClients.createDefault(); HttpPost submitPost = new HttpPost(argoServerUrl + "/api/v1/workflows/default/submit"); submitPost.setHeader("Authorization", "Bearer " + userAccessToken); submitPost.setHeader("Content-Type", "application/json"); submitPost.setEntity(new StringEntity(workflowJson)); HttpResponse response = client.execute(submitPost); // 处理响应 System.out.println("API响应状态: " + response.getStatusLine()); System.out.println("响应内容: " + EntityUtils.toString(response.getEntity())); } }
验证步骤
- 用JWT解析工具检查token,确认
aud字段包含Argo Server配置的客户端ID - 测试API调用,确保返回2xx状态码
内容的提问来源于stack exchange,提问作者Yashwanthkumar Ht
相关产品推荐
相关产品推荐

