欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

使用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"

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。