内网转发钉钉API
1. 问题场景
内网有台服务器A,不能访问外网,但是能通过局域网访问一台具有外网访问功能的服务器B
内网服务器需要访问钉钉API,需要需要通过外网服务器转发。
2. nginx配置转发Https
# 查看nginx版本,确认是否安装了ssl模块
/usr/local/nginx/sbin/nginx -V
nginx配置https需要ssl模块支持,所以nginx没有安装ssl模块需要重新配置
# 进入nginx安装包目录
cd /usr/local/nginx/nginx-1.13.7
# 重新配置模块
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-stream --with-stream_ssl_module
# 安装
make
# 备份已安装的nginx
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
# 暂停nginx
/usr/local/nginx/sbin/nginx -s stop
# 替换安装好的nginx
cp ./objs/nginx /usr/local/nginx/sbin/nginx
# 查看nginx版本,确认是否安装了ssl模块
/usr/local/nginx/sbin/nginx -V
# 切换到nginx程序目录
cd /usr/local/nginx/sbin
# 启动
nginx
生成黑证书
# 查看版本
openssl version
# 输入密码生成私钥
openssl genrsa -des3 -out server.key 2048
# 根据密码生成CSR,需要输入,组织、组织单位、国家、地区、城市和通用名称等信息
openssl req -nodes -new -key server.key -out server.csr
# 生成新证书
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
配置nginx转发
server {
server_name B服务器对应的局域网ip;
listen 11523 ssl;
resolver 114.114.114.114 valid=60s ipv6=off;
ssl_certificate /usr/local/nginx/ssl_key/server.crt;
ssl_certificate_key /usr/local/nginx/ssl_key/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
proxy_pass https://oapi.dingtalk.com;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host 'oapi.dingtalk.com';
proxy_set_header X-Real-IP $remote_addr;
}
location /v1.0/ {
proxy_pass https://api.dingtalk.com;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host 'api.dingtalk.com';
proxy_set_header X-Real-IP $remote_addr;
}
}
3. java 调用https接口
// 解决javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException
// 解决PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException
// 创建一个信任所有证书的 SSLContext 对象
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 不验证客户端证书
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 不验证服务器证书
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}}, new SecureRandom());
// 创建一个跳过证书验证的 SSLSocketFactory 对象
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
// 禁用主体备用名称验证,解决SSLHandshakeException: No subject alternative names present
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
if("B服务器对应的局域网ip".equals(hostname)){
return true;
} else {
return false;
}
}
});
// 发送 HTTPS 请求
URL url = new URL("https://B服务器对应的局域网ip:端口/api具体接口名");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
InputStream input = conn.getInputStream();