使用RestTemplate访问https实现SSL请求操作
程序员文章站
2022-03-09 19:39:02
目录1、添加httpsclientrequestfactory工具类2、修改resttemplate方案二:升级 jdk到1.8版本(推荐方式)方法1: 用java生成证书,不建议,移植性差。方法2:...
方法1: 用java生成证书,不建议,移植性差。
方法2: 将resttemplate改为https请求。
1、添加httpsclientrequestfactory工具类
import org.springframework.http.client.simpleclienthttprequestfactory; import javax.net.ssl.*; import java.io.ioexception; import java.net.httpurlconnection; import java.net.inetaddress; import java.net.socket; import java.security.cert.x509certificate; /** * tls的三个作用: * (1)身份认证 * 通过证书认证来确认对方的身份,防止中间人攻击 * (2)数据私密性 * 使用对称性密钥加密传输的数据,由于密钥只有客户端/服务端有,其他人无法窥探。 * (3)数据完整性 * 使用摘要算法对报文进行计算,收到消息后校验该值防止数据被篡改或丢失。 * * 使用resttemplate进行https请求访问: * private static resttemplate resttemplate = new resttemplate(new httpsclientrequestfactory()); * */ public class httpsclientrequestfactory extends simpleclienthttprequestfactory { @override protected void prepareconnection(httpurlconnection connection, string httpmethod) { try { if (!(connection instanceof httpsurlconnection)) { throw new runtimeexception("an instance of httpsurlconnection is expected"); } httpsurlconnection httpsconnection = (httpsurlconnection) connection; trustmanager[] trustallcerts = new trustmanager[]{ new x509trustmanager() { @override public java.security.cert.x509certificate[] getacceptedissuers() { return null; } @override public void checkclienttrusted(x509certificate[] certs, string authtype) { } @override public void checkservertrusted(x509certificate[] certs, string authtype) { } } }; sslcontext sslcontext = sslcontext.getinstance("tls"); sslcontext.init(null, trustallcerts, new java.security.securerandom()); httpsconnection.setsslsocketfactory(new mycustomsslsocketfactory(sslcontext.getsocketfactory())); httpsconnection.sethostnameverifier(new hostnameverifier() { @override public boolean verify(string s, sslsession sslsession) { return true; } }); super.prepareconnection(httpsconnection, httpmethod); } catch (exception e) { e.printstacktrace(); } } private static class mycustomsslsocketfactory extends sslsocketfactory { private final sslsocketfactory delegate; public mycustomsslsocketfactory(sslsocketfactory delegate) { this.delegate = delegate; } // 返回默认启用的密码套件。除非一个列表启用,对ssl连接的握手会使用这些密码套件。 // 这些默认的服务的最低质量要求保密保护和服务器身份验证 @override public string[] getdefaultciphersuites() { return delegate.getdefaultciphersuites(); } // 返回的密码套件可用于ssl连接启用的名字 @override public string[] getsupportedciphersuites() { return delegate.getsupportedciphersuites(); } @override public socket createsocket(final socket socket, final string host, final int port, final boolean autoclose) throws ioexception { final socket underlyingsocket = delegate.createsocket(socket, host, port, autoclose); return overrideprotocol(underlyingsocket); } @override public socket createsocket(final string host, final int port) throws ioexception { final socket underlyingsocket = delegate.createsocket(host, port); return overrideprotocol(underlyingsocket); } @override public socket createsocket(final string host, final int port, final inetaddress localaddress, final int localport) throws ioexception { final socket underlyingsocket = delegate.createsocket(host, port, localaddress, localport); return overrideprotocol(underlyingsocket); } @override public socket createsocket(final inetaddress host, final int port) throws ioexception { final socket underlyingsocket = delegate.createsocket(host, port); return overrideprotocol(underlyingsocket); } @override public socket createsocket(final inetaddress host, final int port, final inetaddress localaddress, final int localport) throws ioexception { final socket underlyingsocket = delegate.createsocket(host, port, localaddress, localport); return overrideprotocol(underlyingsocket); } private socket overrideprotocol(final socket socket) { if (!(socket instanceof sslsocket)) { throw new runtimeexception("an instance of sslsocket is expected"); } //((sslsocket) socket).setenabledprotocols(new string[]{"tlsv1.2"}); ((sslsocket) socket).setenabledprotocols(new string[]{"tlsv1", "tlsv1.1", "tlsv1.2"}); return socket; } } }
注意:服务端tls版本要和客户端工具类中定义的一致。(tlsv1.2)
2、修改resttemplate
在使用的时候,将
private static resttemplate resttemplate = new resttemplate();
改为:
private static resttemplate resttemplate = new resttemplate(new httpsclientrequestfactory());
其他代码不变。
也可使用注入的方式:
@configuration public class configbean { @bean public resttemplate getresttemplate() { return new resttemplate(new httpsclientrequestfactory()); } }
3、访问https,抛出的异常
javax.net.ssl.sslhandshakeexception: received fatal alert: handshake_failure解决方案
因为jdk中jce的安全机制导致报的错,需要去oracle官网下载对应的jce包替换jdk中的jce包。
方案一:替换jce包
目录 %java_home%\jre\lib\security里的local_policy.jar,us_export_policy.jar jdk7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html jdk8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html // pub1:/home/myron/jdk1.7.0_80 % cd $java_home/jre/lib/security/ //jce所在jdk的路径 us_export_policy.jar local_policy.jar
方案二:升级 jdk到1.8版本(推荐方式)
// pub1:/home/myron % vi .cshrc setenv java_home /home/myron/jdk1.8.0_211 // pub1:/home/myron % source .cshrc // pub1:/home/myron % java -version java version "1.8.0_211"
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。