如何用Java(Jersey)调用StreamSets Control Hub API获取认证令牌?
解决Jersey客户端获取Auth Token并调用API的问题
嘿,我看你现在卡在用Jersey实现curl里的认证令牌获取步骤了,导致后续调用API时一直碰到"User not authenticated"错误。咱们照着curl的逻辑一步步来拆解实现,很快就能搞定~
1. 先搞懂curl登录命令的核心操作
你的第一条curl命令其实做了这几件关键的事:
- 给登录接口
https://host:18641/security/public-rest/v1/authentication/login发一个POST请求 - 请求体是JSON格式的用户名密码:
{"userName":"NAME", "password": "xxxxx"} - 带着两个必填请求头:
Content-Type:application/json和X-Requested-By:SDC - 从响应的Cookie里抠出带SSO标识的令牌值,存到
sessionToken里给后续接口用
2. 用Jersey写个获取Token的方法
我们单独写一个方法来完成登录并提取令牌,代码直接能用:
import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import org.glassfish.jersey.client.ClientConfig; public static String getAuthToken(String loginUrl, String username, String password) throws Exception { ClientConfig cc = new ClientConfig(); // 这里用你已经写好的JerseywithSSL来处理HTTPS证书,避免SSL报错 Client client = new JerseywithSSL().initClient(cc); // 构造登录用的JSON请求体 String loginJson = String.format("{\"userName\":\"%s\", \"password\": \"%s\"}", username, password); // 发送登录请求 Response loginResponse = client.target(loginUrl) .request(MediaType.APPLICATION_JSON) .header("X-Requested-By", "SDC") .post(Entity.entity(loginJson, MediaType.APPLICATION_JSON)); // 先检查登录是否成功 if (loginResponse.getStatus() != 200) { throw new RuntimeException("登录失败啦,HTTP状态码:" + loginResponse.getStatus()); } // 从响应Cookie里捞SSO令牌(对应curl里的grep SSO操作) String sessionToken = null; for (NewCookie cookie : loginResponse.getCookies().values()) { // 这里要注意:如果curl里的SSO对应的Cookie名是具体的(比如SSO_TOKEN),就把contains改成equals if (cookie.getName().contains("SSO")) { sessionToken = cookie.getValue(); break; } } if (sessionToken == null) { throw new RuntimeException("没从响应Cookie里找到SSO令牌,检查下接口返回的Cookie名对不对"); } // 别忘了关闭资源,避免内存泄漏 loginResponse.close(); client.close(); return sessionToken; }
3. 把Token集成到你现有的上传代码里
现在你只需要在testUploadService方法开头先调用上面的getAuthToken拿到令牌,然后把令牌加到请求头里(对应curl里的X-SS-User-Auth-Token:$sessionToken和X-SS-REST-CALL:true)。
修改点如下:
- 先获取令牌:
// 第一步:调用登录接口拿令牌 String loginUrl = "https://host:18641/security/public-rest/v1/authentication/login"; String sessionToken = getAuthToken(loginUrl, User, Pass);
- 在构建请求头时添加令牌相关的字段,同时可以去掉原来的Basic Auth头(因为API要求用token认证,不是Basic Auth):
invocationBuilder = webTarget.request(); // 注释掉原来的Basic Auth,改用token // invocationBuilder.header("Authorization", "Basic " + USER_PASS); invocationBuilder.header("X-Requested-By","SDC"); invocationBuilder.header("X-SS-REST-CALL", "true"); // 这个头curl里有,必须加 invocationBuilder.header("X-SS-User-Auth-Token", sessionToken); // 核心的令牌头 invocationBuilder.header("Content-type", "multipart/form-data; boundary=" + boundary);
4. 几个要注意的坑
- SSL证书问题:确保你的
JerseywithSSL类能正确处理HTTPS的证书,不然登录请求直接就失败了 - Cookie名称匹配:如果curl里的grep是找具体的Cookie名(比如
SSO_SESSION),记得把代码里的contains("SSO")改成equals("具体Cookie名") - 资源关闭:finally块里的资源关闭最好加个非空判断,避免空指针
- 请求体格式:登录请求必须是JSON,不能用表单或multipart,这点别搞错了
最后,整合后的完整testUploadService方法大概是这样:
public static String testUploadService(String httpURL, File filePath,String User,String Pass,Processing processing) throws Exception { // 第一步:获取认证令牌 String loginUrl = "https://host:18641/security/public-rest/v1/authentication/login"; String sessionToken = getAuthToken(loginUrl, User, Pass); // 原有变量定义 ClientConfig clientConfig = null; Client client = null; WebTarget webTarget = null; Invocation.Builder invocationBuilder = null; Response response = null; FileDataBodyPart fileDataBodyPart = null; FormDataMultiPart formDataMultiPart = null; int responseCode; String responseMessageFromServer = null; String responseString = null; String boundary = "=-=" + System.currentTimeMillis() + "=-="; try{ ClientConfig cc = new ClientConfig(); cc.register(MultiPartFeature.class); try { client = new JerseywithSSL().initClient(cc); } catch (KeyManagementException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } webTarget = client.target(httpURL); // 构造文件上传的multipart内容 fileDataBodyPart = new FileDataBodyPart("file", filePath, MediaType.APPLICATION_OCTET_STREAM_TYPE); formDataMultiPart = new FormDataMultiPart(); formDataMultiPart.bodyPart(fileDataBodyPart); // 构建请求头,添加令牌 invocationBuilder = webTarget.request(); invocationBuilder.header("X-Requested-By","SDC"); invocationBuilder.header("X-SS-REST-CALL", "true"); invocationBuilder.header("X-SS-User-Auth-Token", sessionToken); invocationBuilder.header("Content-type", "multipart/form-data; boundary=" + boundary); try{ response = invocationBuilder.post(Entity.entity(formDataMultiPart, MediaType.MULTIPART_FORM_DATA)); } catch(Exception ex){ ex.printStackTrace(); } responseCode = response.getStatus(); System.out.println("Response code: " + responseCode); if (response.getStatus() != 200) { // 这里可以根据实际情况抛出异常或者处理错误 } System.out.println("Check 6"); responseMessageFromServer = response.getStatusInfo().getReasonPhrase(); System.out.println("ResponseMessageFromServer: " + responseMessageFromServer); System.out.println("Check 7"); processing.setlabel("Finished"); processing.setprogress(100); responseString = response.readEntity(String.class); processing.finished("Server Response Code - "+responseCode + "\n ResponseMessageFromServer: " + responseString); } catch(Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(null, "Error!! \n Make sure you are connected to Dell Internal Network"); processing.dispose(); } finally{ // 安全关闭资源,加非空判断 if (fileDataBodyPart != null) fileDataBodyPart.cleanup(); if (formDataMultiPart != null) { formDataMultiPart.cleanup(); formDataMultiPart.close(); } if (response != null) response.close(); if (client != null) client.close(); } return responseString; }
这样应该就能顺利拿到令牌,然后正常调用API了,不会再报认证错误啦~
内容的提问来源于stack exchange,提问作者Vijay Shekhawat
相关产品推荐
相关产品推荐

