Java 6调用API报SSLPeerUnverifiedException,Java 8正常如何解决?
问题
使用Jersey客户端调用获取Token的API时,Java 8环境下可正常返回响应,但在Java 1.6环境运行时抛出javax.net.ssl.SSLPeerUnverifiedException: 未验证对等方错误。目标API可能运行在Java 8或11环境,更换为Apache HTTP客户端库后问题依旧,需修改代码或配置哪些内容以适配Java 1.6?
原代码
import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.json.JSONObject; import java.io.IOException; import static com.oxdeo.serviceclient.constants.*; public class TokenService { protected final Log logger = LogFactory.getLog(TokenService.class); private static String bodyStr = "grant_type=client_credentials&client_id=" + coreClientId + "&client_secret=" + coreClientSecret; private Client jerseyClient = new Client(); public String getToken() { WebResource webResource = jerseyClient.resource(coreTokenURL); ClientResponse clientResponse = webResource.type("application/x-www-form-urlencoded").post(ClientResponse.class, bodyStr); logger.info("client response token: " + clientResponse.getStatus()); String token = null; if (clientResponse.getStatus() == 200) { token = parseToken(clientResponse); } else { logger.error("Unable to get token. response:" + clientResponse.getStatus()); } return token; } private String parseToken(ClientResponse clientResponse) { String accessToken=""; String responseStr = clientResponse.getEntity(String.class); JSONObject jsonResponse = new JSONObject(responseStr); if(clientResponse.getStatus() >=200 && clientResponse.getStatus() <=204) { accessToken = jsonResponse.getString("access_token"); } return accessToken; } }
错误信息
javax.net.ssl.SSLPeerUnverifiedException: 未验证对等方
解决方案
1. 强制使用Java 1.6兼容的TLS版本
Java 1.6默认仅启用TLS 1.0,而运行在Java 8/11的API可能已禁用该协议版本。需手动指定兼容的TLS版本(若API仍支持TLS 1.0),或安装JDK 1.6的JSSE扩展补丁以支持TLS 1.1/1.2。
2. 导入目标API的根证书到Java 1.6信任库
Java 1.6默认信任库cacerts可能缺少目标API使用的CA根证书,导致SSL验证失败:
- 导出目标API的SSL证书(可通过浏览器或
openssl s_client -connect <域名>:443命令获取) - 使用
keytool命令将证书导入JDK 1.6的jre/lib/security/cacerts:
默认信任库密码为keytool -import -alias <自定义别名> -file <证书路径> -keystore <JDK1.6路径>/jre/lib/security/cacertschangeit。
3. 配置Jersey客户端的自定义SSL上下文
可通过自定义SSL上下文绕过证书验证(仅测试环境使用,生产环境不推荐),或加载自定义信任库,修改后的代码示例:
import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.client.urlconnection.HTTPSProperties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.json.JSONObject; import javax.net.ssl.*; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import static com.oxdeo.serviceclient.constants.*; public class TokenService { protected final Log logger = LogFactory.getLog(TokenService.class); private static String bodyStr = "grant_type=client_credentials&client_id=" + coreClientId + "&client_secret=" + coreClientSecret; private Client jerseyClient; public TokenService() { this.jerseyClient = createSslEnabledClient(); } private Client createSslEnabledClient() { try { // 信任所有证书的TrustManager(测试用) TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {} public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {} } }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); // 绕过域名验证的HostnameVerifier(测试用) HostnameVerifier allHostsValid = (hostname, session) -> true; Client client = Client.create(); HTTPSProperties httpsProperties = new HTTPSProperties(allHostsValid, sslContext); client.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties); return client; } catch (Exception e) { logger.error("Failed to create SSL enabled client", e); return Client.create(); } } public String getToken() { WebResource webResource = jerseyClient.resource(coreTokenURL); ClientResponse clientResponse = webResource.type("application/x-www-form-urlencoded").post(ClientResponse.class, bodyStr); logger.info("client response token: " + clientResponse.getStatus()); String token = null; if (clientResponse.getStatus() == 200) { token = parseToken(clientResponse); } else { logger.error("Unable to get token. response:" + clientResponse.getStatus()); } return token; } private String parseToken(ClientResponse clientResponse) { String accessToken=""; String responseStr = clientResponse.getEntity(String.class); JSONObject jsonResponse = new JSONObject(responseStr); if(clientResponse.getStatus() >=200 && clientResponse.getStatus() <=204) { accessToken = jsonResponse.getString("access_token"); } return accessToken; } }
4. 安装JDK 1.6的JSSE扩展补丁
Oracle官方为JDK 1.6提供了支持TLS 1.1/1.2的扩展补丁,安装后可让Java 1.6支持更高版本的TLS协议,解决协议版本不兼容导致的SSL验证失败。
内容的提问来源于stack exchange,提问作者ANJ
相关产品推荐
相关产品推荐

