diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bestsign/RegisterController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bestsign/RegisterController.java new file mode 100644 index 0000000..eef7abd --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bestsign/RegisterController.java @@ -0,0 +1,30 @@ +package com.ruoyi.web.controller.bestsign; + +import com.ruoyi.bestsign.domain.PersonRegisterVO; +import com.ruoyi.bestsign.service.SignRegisterService; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.wisdomarbitrate.domain.CaseApplication; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/register") +public class RegisterController { + @Autowired + SignRegisterService signRegisterService; + + /** + * 注册上上签个人用户 + * + * @param personRegisterVO + * @return + */ + @PostMapping("/registerPerson") + public AjaxResult createDocument(@Validated @RequestBody PersonRegisterVO personRegisterVO) { + return signRegisterService.registerPerson(personRegisterVO); + } +} diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 822641d..cbbed36 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -102,6 +102,11 @@ spring: smtp: socketFactoryClass: javax.net.ssl.SSLSocketFactory debug: false +#上上签配置参数 +ssq: + developerId: 1695872832013855470 + privateKey: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCiDRuz+dxqkWqHdov0hK+KEWLw/e8MQSqkZZ4c01Yr6cSmQiWyV8Xin0u5S/EA02FWxpjLi1nLriVtOBhZGsoryFmcJrwzSnQ5PORP/HhfcAWFE/Y+3qSQS1OiU7e5wbReCgEUvx4GHZuhdu8cOvq5DG9l33YFZrIEMBTmnf8eKT54STx0tjcKl7U6B6nsiThy3zVtpWXVv6H1HGmxC0KT4EQ388s/PFjrwmk+GFb3EpKCns/GQHf7QrtNz1ZOgCXfgQiQ+91/tcngzUH+zMCIxn5lS+ENAxVI6Ev3W9Y0QHtKwmO4ORVuAskJYzBB2xKI/gw8+PUXNziMAKXuoUAjAgMBAAECggEAd7yHw6vTGUrpE76cGsgPjEzcdoSqpLth7qbG9TWSblAEZXRqtiP0q0ZYhUl/gcSuH5gOPhdw+fZq4RCZrP0GdONMkvxsAtn4lnJPoGpD5wC2k2X0hO+tWJDP8xk4n6BozTNHKTUt0gb+f4eJlapep2xwwy0h30vKLR3504zafEV9j/2D8l5TFSv6rd3UVxUvrDKQ9mhfATEUlrTpjs0SfWupMkr4j7TuJJ8qSUSiEADe4hyUB6+LouDZCt8jV4aLojQBJKrQ6VPVdDFkHGsePu4tHtvcKsaOZJ0pjpJ7MT6D5ElD/sJjo0g/3qK5/FToVFVbrxtykVreK6mE5oSTQQKBgQDpEFSgH1d4N7NsZhviaCIUkB97hO0jpRbD7UZirzZ9ok96Fk+SmfhdmypDMoiaRHCNhQuu5dI9mg5RbUhz9mCZnAhzJRL+DmE4bhNvQmbtJA7KT6n/AdH2zy0mYulrcG17dQspvTr/5421PTEE2+FRoCbG6hBsSSUit9HLvAU13QKBgQCx/7ql+hbx+t0Yb02XckBHiA+MWrFLO4dMX9cKf3LldC0nhn0K9HOSoZmM0KcmXRnMo+/4t89xOJRl7JRXwcLoy/64OaUBVv+8FFV1yY4THka3nEnQE40vVWy+vuNJtt+eKlEhJ35N1GIHXo7/4j0POtEuNU7KSqMnLUD+Oy/t/wKBgEiajcJUASuyLnLWXFlrlzJQs34HKtiv1Se0Avk7G/6HUbr2uFMzI+wFKmVEmMl2CJoNmFYjwhruowc6xBdb6TvxH7C/G+uJD0BFCkjeprG5SeI8bvjB2GbKo4YRyiVuIK0VCSU3jemqeLq9FUguN0L2YR4WTIdvQeJO4UxWhkkBAoGBAJk7TxDHZK1XirIYTzGK928c4FWxVWMwkd7buqGc6epBwwV9r3OY0U1vtGIW1W4fQ7B5iIISqpALZyT/Lw0FDqedxWAOr8+hd3IQBynpI1et/q7d6mUoD6ip332tkrjIp2TfhQwHlaGmreUuL+h0eJ/9wEoJNhTLf/yf5o11omM9AoGBAOLVlXR9FbU2Ubpp3HwTumSzKDWzq3T5eQcqC1zE3BPOo29uAf9BQTumPxe51U64egttW/nif5FH4v4Gentmxb2B2ckdOs/u9zIWz3JPfHU7RqMyMokuWrQ6lMoiSYpH3MSHoavLyAEhAnpceX3oktXgpYHO9d8MfON3XKJl23ip + serverHost: http://openapi.bestsign.info/openapi/v2/ # token配置 token: diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/domain/CredentialVO.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/domain/CredentialVO.java new file mode 100644 index 0000000..c9fba91 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/domain/CredentialVO.java @@ -0,0 +1,22 @@ +package com.ruoyi.bestsign.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class CredentialVO { + /** + * 用户证件号 + */ + private String identity; + /** + * 用户证件类型 + * 默认用“0”, "0"表示身份证,会校验18位身份证号格式。0-居民身份证; 1-护照;6-社会保障卡; B-港澳居民往来内地通行证; C-台湾居民来往大陆通行证; E-户口簿; F-临时居民身份证;P-外国人永久居留证;Z-其他证件 + */ + private String identityType; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/domain/PersonRegisterVO.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/domain/PersonRegisterVO.java new file mode 100644 index 0000000..159bcd4 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/domain/PersonRegisterVO.java @@ -0,0 +1,29 @@ +package com.ruoyi.bestsign.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class PersonRegisterVO { + /** + * 用户帐号 + * 用户名称 + * 用户类型 + * 用户邮箱 + * 用户手机号 + * 用户证件信息对象 + * 是否申请证书 + */ + private String account; + private String name; + private String userType; + private String mail; + private String mobile; + private CredentialVO credential; + private String applyCert; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/service/SignRegisterService.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/service/SignRegisterService.java new file mode 100644 index 0000000..e0eb419 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/service/SignRegisterService.java @@ -0,0 +1,14 @@ +package com.ruoyi.bestsign.service; + +import com.ruoyi.bestsign.domain.PersonRegisterVO; +import com.ruoyi.common.core.domain.AjaxResult; + +public interface SignRegisterService { + /** + * 注册上上签个人用户 + * + * @param personRegisterVO + * @return + */ + AjaxResult registerPerson(PersonRegisterVO personRegisterVO); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/service/impl/RegisterServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/service/impl/RegisterServiceImpl.java new file mode 100644 index 0000000..d00cdf9 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/service/impl/RegisterServiceImpl.java @@ -0,0 +1,39 @@ +package com.ruoyi.bestsign.service.impl; + + +import com.ruoyi.bestsign.domain.PersonRegisterVO; +import com.ruoyi.bestsign.service.SignRegisterService; +import com.ruoyi.bestsign.utils.BestsignOpenApiClient; +import com.ruoyi.common.core.domain.AjaxResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class RegisterServiceImpl implements SignRegisterService { + @Autowired + BestsignOpenApiClient bestsignOpenApiClient; + + /** + * 注册上上签个人用户 + * + * @param personRegisterVO + * @return + */ + @Override + public AjaxResult registerPerson(PersonRegisterVO personRegisterVO) { + try { + String s = bestsignOpenApiClient.userPersonalReg(personRegisterVO.getAccount(), + personRegisterVO.getName(), + personRegisterVO.getMail(), + personRegisterVO.getMobile(), + personRegisterVO.getCredential().getIdentity(), + personRegisterVO.getCredential().getIdentityType(), + null, null, null, null, null); + AjaxResult.success(s); + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error(e.getMessage()); + } + return AjaxResult.success(); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/BestsignOpenApiClient.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/BestsignOpenApiClient.java new file mode 100644 index 0000000..7c09e67 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/BestsignOpenApiClient.java @@ -0,0 +1,148 @@ +package com.ruoyi.bestsign.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +/** + * 上上签混合云SDK客户端 + */ +@Component +@Data +@Slf4j +public class BestsignOpenApiClient { + /** + * 开发者id + */ + @Value("${ssq.developerId}") + private String developerId; + /** + * 开发者私钥 + */ + @Value("${ssq.privateKey}") + private String privateKey; + /** + * Host地址 + */ + @Value("${ssq.serverHost}") + private String serverHost; + private static String urlSignParams = "?developerId=%s&rtick=%s&signType=rsa&sign=%s"; + +// public BestsignOpenApiClient(String developerId, String privateKey, +// String serverHost) { +// this.developerId = developerIds; +// this.privateKey = privateKey; +// this.serverHost = serverHost; +// } + + /** + * POST方法示例 + * 个人用户注册 + * + * @param account 用户账号 + * @param name 姓名 + * @param mail 用来接收通知邮件的电子邮箱 + * @param mobile 用来接收通知短信的手机号码 + * @param identity 证件号码 + * @param identityType 枚举值:0-身份证,目前仅支持身份证 + * @param contactMail 电子邮箱 + * @param contactMobile 手机号码 + * @param province 省份 + * @param city 城市 + * @param address 地址 + * @return 异步申请任务单号 + * @throws IOException + */ + public String userPersonalReg(String account, String name, String mail, + String mobile, String identity, String identityType, + String contactMail, String contactMobile, String province, + String city, String address) throws Exception { + String host = this.serverHost; + String method = "/user/reg/"; + + // 组装请求参数,作为requestbody + JSONObject requestBody = new JSONObject(); + requestBody.put("account", account); + requestBody.put("name", name); + requestBody.put("userType", "1"); + requestBody.put("mail", mail); + requestBody.put("mobile", mobile); + + JSONObject credential = new JSONObject(); + credential.put("identity", identity); + credential.put("identityType", identityType); + credential.put("contactMail", contactMail); + credential.put("contactMobile", contactMobile); + credential.put("province", province); + credential.put("city", city); + credential.put("address", address); + requestBody.put("credential", credential); + //是否申请证书 + requestBody.put("applyCert", "2"); + // 生成一个时间戳参数 + String rtick = RSAUtils.getRtick(); + // 计算参数签名 + String paramsSign = RSAUtils.calcRsaSign(this.developerId, + this.privateKey, this.serverHost, method, rtick, null, + requestBody.toJSONString()); + // 签名参数追加为url参数 + String fullUrlParams = String.format(urlSignParams, this.developerId, + rtick, paramsSign); + + // 发送POST请求 + String responseBody = HttpClientSender.sendHttpPost(this.serverHost, method, + fullUrlParams, requestBody.toJSONString()); + System.out.println(responseBody); + // 返回结果解析 + JSONObject userObj = JSON.parseObject(responseBody); + // 返回errno为0,表示成功,其他表示失败 + if (userObj.getIntValue("errno") == 0) { + JSONObject data = userObj.getJSONObject("data"); + if (data != null) { + //对返回data进行处理 + String taskId = data.getString("taskId"); + return taskId; + } + } else { + //接口返回异常 + System.out.println(userObj.getIntValue("errno")); + System.out.println(userObj.getString("errmsg")); + } + return userObj.toJSONString(); + } + + /** + * GET方法示例 + * 下载合同PDF文件 + * + * @param contractId 合同编号 + * @return + * @throws Exception + */ + public byte[] contractDownload(String contractId) throws Exception { + String host = this.serverHost; + String method = "/storage/contract/download/"; + + // 组装url参数 + String urlParams = "contractId=" + contractId; + + // 生成一个时间戳参数 + String rtick = RSAUtils.getRtick(); + // 计算参数签名 + String paramsSign = RSAUtils.calcRsaSign(this.developerId, + this.privateKey, host, method, rtick, urlParams, null); + // 签名参数追加为url参数 + urlParams = String.format(urlSignParams, this.developerId, rtick, + paramsSign) + "&" + urlParams; + // 发送请求 + byte[] responseBody = HttpClientSender.sendHttpGet(host, method, + urlParams); + // 返回结果解析 + return responseBody; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/HttpClientSender.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/HttpClientSender.java new file mode 100644 index 0000000..3a1af73 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/HttpClientSender.java @@ -0,0 +1,390 @@ +package com.ruoyi.bestsign.utils; + +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; + +public class HttpClientSender { + + private static PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = null; + private static Map httpClients = new HashMap(); + + private static Object o = new Object(); + + public static String sendHttpPost(String host, String method, String urlParams, String sendData) throws IOException { + + String requestUrl = host + method + urlParams; + + Map response = request("POST", requestUrl, sendData, null); + int responseCode = Integer.parseInt(response.get("responseCode").toString()); + byte[] responseBytes = (byte[]) response.get("responseData"); + String responseString; + try { + responseString = new String(responseBytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + responseString = new String(responseBytes); + } + //请求返回结果无论成功失败,http-status均为200 + if (responseCode == 200) { + //返回结果 + return responseString; + } else { + throw new IOException(responseCode + ":" + responseString); + } + } + + public static byte[] sendHttpGet(String host, String method, String urlParams) throws IOException { + String requestUrl = host + method + urlParams; + Map response = request("GET", requestUrl, null, null); + int responseCode = Integer.parseInt(response.get("responseCode").toString()); + byte[] responseBytes = (byte[]) response.get("responseData"); + //请求返回结果无论成功失败,http-status均为200 + if (responseCode == 200) { + //返回结果 + return responseBytes; + } else { + throw new IOException(responseCode + ""); + } + } + + public static String urlencode(String data) { + return urlencode(data, "UTF-8"); + } + + public static String urlencode(String data, String charset) { + try { + return URLEncoder.encode(data, charset); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public static Map request(String method, String url, Object sendData, Map headers) throws IOException { + + + String requestPath; + try { + requestPath = new URL(url).getPath(); + } catch (MalformedURLException e) { + throw new RuntimeException(e.getMessage(), e); + } + CloseableHttpClient httpClient = getHttpClient(requestPath); + + Map response = null; + if ("POST".equals(method)) { + response = sendPost(httpClient, url, headers, sendData); + } else { + response = sendGet(httpClient, url, headers); + } + return response; + } + + private static Map sendPost(CloseableHttpClient httpClient, String url, Map headers, Object sendData) throws IOException { + String tag = "[HttpRequester] [POST " + url + "]"; + int responseCode = -1; + byte[] responseBytes = null; + + HttpPost request = new HttpPost(url); + if (headers != null && headers.size() > 0) { + for (String name : headers.keySet()) { + String value = headers.get(name); + request.setHeader(name, value); + } + } + if (sendData != null) { + StringEntity stringEntity = new StringEntity((String) sendData, "UTF-8"); + stringEntity.setContentType("application/json"); + request.setEntity(stringEntity); + + HttpEntity httpEntity = null; + IOException exception = null; + for (int i = 0; i < 3; i++) { + try { + CloseableHttpResponse response = httpClient.execute(request); + responseCode = response.getStatusLine().getStatusCode(); + httpEntity = response.getEntity(); + + String responseBody = EntityUtils.toString(httpEntity, "utf-8"); + if (responseBody != null) { + responseBytes = responseBody.getBytes(); + } else { + InputStream respStream = null; + try { + respStream = httpEntity.getContent(); + int respBodySize = respStream.available(); + if (respBodySize <= 0) + throw new IOException("Invalid respBodySize: " + respBodySize); + responseBytes = new byte[respBodySize]; + if (respStream.read(responseBytes) != respBodySize) + throw new IOException("Read respBody Error"); + } catch (Exception e) { + } finally { + if (respStream != null) { + respStream.close(); + } + } + } + + exception = null; + break; + } catch (UnsupportedOperationException e) { + try { + EntityUtils.consume(httpEntity); + } catch (IOException e2) { + + } + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) { + e.printStackTrace(); + exception = e; + try { + EntityUtils.consume(httpEntity); + } catch (IOException e2) { + + } + if (i < 2) { + try { + Thread.sleep(5); + } catch (InterruptedException e2) { + + } + } + } + } + if (exception != null) { + throw exception; + } + + } + Map response = new HashMap(); + response.put("responseCode", responseCode); + response.put("responseData", responseBytes); + String loggerResponseString = getLoggerString(responseBytes, 256); + return response; + } + + private static Map sendGet(CloseableHttpClient httpClient, String url, Map headers) throws IOException { + String tag = "[HttpRequester] [GET " + url + "]"; + int responseCode = -1; + byte[] responseBytes = null; + + HttpGet request = new HttpGet(url); + if (headers != null && headers.size() > 0) { + for (String name : headers.keySet()) { + String value = headers.get(name); + request.setHeader(name, value); + } + } + HttpEntity httpEntity = null; + IOException exception = null; + for (int i = 0; i < 3; i++) { + try { + CloseableHttpResponse response = httpClient.execute(request); + responseCode = response.getStatusLine().getStatusCode(); + httpEntity = response.getEntity(); + + byte[] responseBody = EntityUtils.toByteArray(httpEntity); + if (responseBody != null) { + responseBytes = responseBody; + } else { + InputStream respStream = null; + try { + respStream = httpEntity.getContent(); + int respBodySize = respStream.available(); + if (respBodySize <= 0) + throw new IOException("Invalid respBodySize: " + respBodySize); + responseBytes = new byte[respBodySize]; + if (respStream.read(responseBytes) != respBodySize) + throw new IOException("Read respBody Error"); + } catch (Exception e) { + } finally { + if (respStream != null) { + respStream.close(); + } + } + } + + exception = null; + break; + } catch (UnsupportedOperationException e) { + try { + EntityUtils.consume(httpEntity); + } catch (IOException e2) { + + } + throw new RuntimeException(e.getMessage(), e); + } catch (IOException e) { + e.printStackTrace(); + exception = e; + try { + EntityUtils.consume(httpEntity); + } catch (IOException e2) { + + } + if (i < 2) { + try { + Thread.sleep(5); + } catch (InterruptedException e2) { + + } + } + } + } + if (exception != null) { + throw exception; + } + Map response = new HashMap(); + response.put("responseCode", responseCode); + response.put("responseData", responseBytes); + String loggerResponseString = getLoggerString(responseBytes, 256); + System.out.println(tag + " response " + responseCode + " " + loggerResponseString); + return response; + } + + private static String getLoggerString(final byte[] data, int maxLength) { + String loggerString; + if (data.length > maxLength) { + byte[] shortData = new byte[maxLength]; + System.arraycopy(data, 0, shortData, 0, shortData.length); + try { + loggerString = new String(shortData, "UTF-8") + "..."; + } catch (UnsupportedEncodingException e) { + loggerString = new String(shortData) + "..."; + } + } else { + try { + loggerString = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + loggerString = new String(data); + } + } + + char[] chars = new char[loggerString.length()]; + loggerString.getChars(0, loggerString.length(), chars, 0); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (c == '\n' || c == '\r') { + chars[i] = ' '; + } + } + return new String(chars); + } + + private static CloseableHttpClient getHttpClient(String requestPath) { + if (httpClients.containsKey(requestPath)) { + return httpClients.get(requestPath); + } + if (poolingHttpClientConnectionManager == null) { + synchronized (o) { + if (poolingHttpClientConnectionManager == null) { + poolingHttpClientConnectionManager = HttpClientUtils.createHttpClientConnectionManager(); + } + } + } + synchronized (httpClients) { + if (httpClients.containsKey(requestPath)) { + return httpClients.get(requestPath); + } + CloseableHttpClient httpClient = HttpClientUtils.createHttpClient(poolingHttpClientConnectionManager); + httpClients.put(requestPath, httpClient); + return httpClient; + } + } + + private static class HttpClientUtils { + + // 默认连接超时 + private static int defaultConnectTimeout = 6000; + // 默认读取超时 + private static int defaultReadTimeout = 30000; + + public static CloseableHttpClient createHttpClient(PoolingHttpClientConnectionManager connManager) { + //HttpHost httpHost = new HttpHost("10.211.55.4", 8888); + CloseableHttpClient httpClient = HttpClients.custom() + //.setProxy(httpHost) + .setConnectionManager(connManager) + .disableContentCompression() + .setSSLContext(getSslcontext()) + .setDefaultRequestConfig(getRequestConfig()) + .build(); + return httpClient; + } + + public static PoolingHttpClientConnectionManager createHttpClientConnectionManager() { + SSLConnectionSocketFactory sslConnectionSocketFactory = null; + try { + sslConnectionSocketFactory = new SSLConnectionSocketFactory(getSslcontext(), SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("https", sslConnectionSocketFactory) + .register("http", new PlainConnectionSocketFactory()) + .build(); + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + cm.setMaxTotal(500); + cm.setDefaultMaxPerRoute(500); + return cm; + } + + private static RequestConfig getRequestConfig() { + RequestConfig defaultRequestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(defaultConnectTimeout) + .setSocketTimeout(defaultReadTimeout) + .build(); + return defaultRequestConfig; + } + + private static SSLContext getSslcontext() { + SSLContext sslContext = null; + try { + sslContext = SSLContext.getInstance("TLS"); + TrustManager tm = new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + sslContext.init(null, new TrustManager[]{tm}, null); + + } catch (Exception e) { + e.printStackTrace(); + } + return sslContext; + } + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/RSAUtils.java b/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/RSAUtils.java new file mode 100644 index 0000000..957e1fb --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/bestsign/utils/RSAUtils.java @@ -0,0 +1,281 @@ +package com.ruoyi.bestsign.utils; + +import org.apache.commons.codec.binary.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; + +/** + * 参数签名算法工具类 + */ +public class RSAUtils { + + /** + * 获取当前的时间戳参数 + * @return + */ + public static String getRtick(){ + long timestamp = System.currentTimeMillis(); + int rnd = (int)Math.random() * 1000; + String rtick = timestamp + "" + rnd; + return rtick; + } + + /** + * 计算参数签名 + * @param developerId 开发者ID + * @param privateKey 用户私钥 + * @param host 请求的HOST地址(http://ip:port/context) + * @param methodName 请求的接口方法名 + * @param rtick 时间戳参数 + * @param urlParams url参数(param1=value1¶m2=value2¶m3=value3) + * @param requestBody request body 参数(JSON字符串) + * @return + */ + public static String calcRsaSign(String developerId, String privateKey, String host, String methodName, String rtick, String urlParams, String requestBody) { + String url = host+methodName; + + Map mySignedURLParams = new TreeMap(); + mySignedURLParams.put("developerId", developerId); + mySignedURLParams.put("rtick", rtick); + mySignedURLParams.put("signType", "rsa"); + + if(urlParams != null && !"".equals(urlParams)){ + String[] params = urlParams.split("&"); + for(String p1 : params){ + String[] p2 = p1.split("="); + String key = p2[0]; + String value = ""; + if(p2.length == 2){ + value = p2[1]; + } + mySignedURLParams.put(key, value); + } + } + + String requestPath; + try { + requestPath = new URL(url).getPath(); + } + catch (MalformedURLException e) { + throw new RuntimeException(e.getMessage(), e); + } + + StringBuilder signStringBuilder = new StringBuilder(); + for (String name : mySignedURLParams.keySet()) { + String value = mySignedURLParams.get(name); + signStringBuilder.append(name); + signStringBuilder.append("="); + signStringBuilder.append(value); + } + signStringBuilder.append(requestPath); + + if (requestBody != null && !"".equals(requestBody) ) { + String requestMd5 = getRequestMd5(requestBody); + signStringBuilder.append(requestMd5); + } + + String signString = signStringBuilder.toString(); + String rsaSign = calcRsaSign(privateKey, signString); + //rsa算出来的sign,需要urlencode + try { + rsaSign = URLEncoder.encode(rsaSign,"UTF-8"); + } catch (UnsupportedEncodingException e) { + rsaSign = null; + } + return rsaSign; + } + + /** + * 获取request body 的MD5 + * @param requestBody + * @return + */ + private static String getRequestMd5(final String requestBody) { + byte[] data; + + String newRequestBody = convertToUtf8(requestBody); + try { + data = newRequestBody.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + return md5(data); + } + + /** + * 计算参数RSA签名 + * @param privateKey + * @param signData + * @return + */ + private static String calcRsaSign(String privateKey, final String signData) { + byte[] data; + try { + data = signData.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + byte[] sign = null; + // 解密由base64编码的私钥 + byte[] privateKeyBytes = base64decode(privateKey.getBytes()); + + // 构造PKCS8EncodedKeySpec对象 + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); + + // KEY_ALGORITHM 指定的加密算法 + KeyFactory keyFactory; + try { + keyFactory = KeyFactory.getInstance("RSA"); + } + catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e.getMessage(), e); + } + + // 取私钥匙对象 + PrivateKey priKey; + try { + priKey = keyFactory.generatePrivate(pkcs8KeySpec); + } + catch (InvalidKeySpecException e) { + throw new RuntimeException(e.getMessage(), e); + } + + // 用私钥对信息生成数字签名 + Signature signature; + try { + signature = Signature.getInstance("SHA1withRSA"); + } + catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e.getMessage(), e); + } + try { + signature.initSign(priKey); + } + catch (InvalidKeyException e) { + throw new RuntimeException(e.getMessage(), e); + } + + try { + signature.update(data); + sign = signature.sign(); + } + catch (SignatureException e) { + throw new RuntimeException(e.getMessage(), e); + } + return new String(base64encode(sign)); + } + + /** + * 转换字符集到utf8 + * + * @param src + * @return + */ + private static String convertToUtf8(String src) { + if (src == null || src.length() == 0) { + return src; + } + if ("UTF-8".equalsIgnoreCase(Charset.defaultCharset().name())) { + return src; + } + + byte[] srcData = src.getBytes(); + try { + return new String(srcData, "UTF-8"); + } + catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * md5 + * @param data + * @return + */ + public static String md5(byte[] data) { + char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + byte[] btInput = data; + // 获得MD5摘要算法的 MessageDigest 对象 + MessageDigest mdInst; + try { + mdInst = MessageDigest.getInstance("MD5"); + } + catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e.getMessage(), e); + } + // 使用指定的字节更新摘要 + mdInst.update(btInput); + // 获得密文 + byte[] md = mdInst.digest(); + // 把密文转换成十六进制的字符串形式 + int j = md.length; + char str[] = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } + + /** + * base64编码 + * @param data + * @return + */ + public static byte[] base64encode(byte[] data) { + return Base64.encodeBase64(data); + } + + /** + * base64编码字符串 + * @param data + * @return + */ + public static String base64encodeString(byte[] data) { + return Base64.encodeBase64String(data); + } + + /** + * base64解码 + * @param data + * @return + */ + public static byte[] base64decode(byte[] data) { + try { + return Base64.decodeBase64(data); + } catch (Exception e) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + for (int i = 0; i < data.length; i++) { + byte c = data[i]; + if (c == 13 || c == 10) { + continue; + } + outputStream.write(c); + } + try { + outputStream.close(); + } catch (IOException e2) { + + } + data = outputStream.toByteArray(); + return Base64.decodeBase64(data); + } + } +}