src/main/java/org/springblade/common/utils/HttpClientUtils.java
@@ -391,7 +391,7 @@ } //适用于post请求并传送form-data数据(同样适用于post的Raw类型的application-json格式) public static String postParams(String url, String appKey, String appKeyValue, Map<String, String> map) { public static String postParams(String url, String appKey, Map<String, String> map) { SSLContext sslcontext = null; try { sslcontext = createIgnoreVerifySSL(); @@ -412,7 +412,7 @@ //创建自定义的httpclient对象 CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build(); HttpPost post = new HttpPost(url); post.setHeader(appKey, appKeyValue); post.setHeader("appKey", appKey); CloseableHttpResponse res = null; try { List<NameValuePair> nvps = new ArrayList<NameValuePair>(); src/main/java/org/springblade/common/utils/Md5SignUtil.java
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.security.MessageDigest; import java.util.Arrays; import java.util.Map; @@ -51,4 +52,47 @@ return sign.toString(); } /*** * MD5加码 生成32位md5码 */ public static String string2MD5(String inStr) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { e.printStackTrace(); return ""; } char[] charArray = inStr.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) { byteArray[i] = (byte) charArray[i]; } byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } /** * 加密解密算法 执行一次加密,两次解密 */ public static String convertMD5(String inStr) { char[] a = inStr.toCharArray(); for (int i = 0; i < a.length; i++) { a[i] = (char) (a[i] ^ 't'); } String s = new String(a); return s; } } src/main/java/org/springblade/common/utils/RSAUtils.java
New file @@ -0,0 +1,215 @@ package org.springblade.common.utils; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URLDecoder; import java.net.URLEncoder; import java.security.InvalidParameterException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import javax.crypto.Cipher; import org.apache.commons.lang3.StringUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; /** * RSA算法加密/解密工具类。 * 以下代码可以使用,唯一需要注意的是: org.bouncycastle...这个jar包需要找一到放到项目中,RSA所需jar包在java中已经自带了. * * @author liuyan */ public class RSAUtils { /** * 算法名称 */ private static final String ALGORITHOM = "RSA"; /** * 密钥大小 */ private static final int KEY_SIZE = 1024; /** * 默认的安全服务提供者 */ private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider(); private static KeyPairGenerator keyPairGen = null; private static KeyFactory keyFactory = null; /** * 缓存的密钥对。 */ private static KeyPair oneKeyPair = null; //密文种子, 当想更换RSA钥匙的时候,只需要修改密文种子,即可更换 private static final String radamKey = "你自己随便写上数字或者英文即可"; //类加载后进行初始化数据 static { try { keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER); keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER); } catch (NoSuchAlgorithmException ex) { ex.printStackTrace(); } } /** * 根据指定的密文种子,生成并返回RSA密钥对。 */ private static synchronized KeyPair generateKeyPair() { try { keyPairGen.initialize(KEY_SIZE, new SecureRandom(radamKey.getBytes())); oneKeyPair = keyPairGen.generateKeyPair(); return oneKeyPair; } catch (InvalidParameterException ex) { ex.printStackTrace(); } catch (NullPointerException ex) { ex.printStackTrace(); } return null; } /** * 返回初始化时默认的公钥。 */ public static RSAPublicKey getDefaultPublicKey() { KeyPair keyPair = generateKeyPair(); if (keyPair != null) { return (RSAPublicKey) keyPair.getPublic(); } return null; } /** * 使用指定的私钥解密数据。 * * @param privateKey 给定的私钥。 * @param data 要解密的数据。 * @return 原数据。 */ public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception { Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER); ci.init(Cipher.DECRYPT_MODE, privateKey); return ci.doFinal(data); } /** * 使用默认的私钥解密给定的字符串。 * @param encryptText 密文。 * @return 原文字符串。 */ public static String decryptString(String encryptText) { if (StringUtils.isBlank(encryptText)) { return null; } KeyPair keyPair = generateKeyPair(); try { byte[] en_data = Hex.decode(encryptText); byte[] data = decrypt((RSAPrivateKey) keyPair.getPrivate(), en_data); return new String(data); } catch (NullPointerException ex) { ex.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } return null; } /** * 使用秘钥 - 对js端传递过来密文进行解密 * * @param encryptText 密文。 * @return {@code encryptText} 的原文字符串。 */ public static String decryptStringByJs(String encryptText) { String text = decryptString(encryptText); if (text == null) { return null; } String reverse = StringUtils.reverse(text); String decode = null; try { //这里需要进行编码转换.注:在前端js对明文加密前需要先进行转码-可自行百度"编码转换" decode = URLDecoder.decode(reverse, "UTF-8"); System.out.println("解密后文字:" + decode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return decode; } //java端 - 使用公钥进行加密 public static byte[] encrypt(String plaintext) throws Exception { // 获取公钥及参数e,n RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey(); //获取公钥指数 e BigInteger e = publicKey.getPublicExponent(); //获取公钥系数 n BigInteger n = publicKey.getModulus(); //先将明文进行编码 String encode = URLEncoder.encode(plaintext); // 获取明文字节数组 m BigInteger m = new BigInteger(encode.getBytes()); // 进行明文加密 c BigInteger c = m.modPow(e, n); //返回密文字节数组 return c.toByteArray(); } //java端 - 使用私钥进行解密 public static String decrypt(byte[] cipherText) throws Exception { // 读取私钥 KeyPair keyPair = generateKeyPair(); RSAPrivateKey prk = (RSAPrivateKey) keyPair.getPrivate(); // 获取私钥参数-指数/系数 BigInteger d = prk.getPrivateExponent(); BigInteger n = prk.getModulus(); // 读取密文 BigInteger c = new BigInteger(cipherText); // 进行解密 BigInteger m = c.modPow(d, n); // 解密结果-字节数组 byte[] mt = m.toByteArray(); //转成String,此时是乱码 String en = new String(mt); //再进行编码 String result = java.net.URLDecoder.decode(en, "UTF-8"); //最后返回解密后得到的明文 return result; } public static void main(String[] args) { /*解密js端传递过来的密文*/ //获取公钥对象--注意:前端那边需要用到公钥系数和指数 RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey(); //公钥-系数(n) System.out.println("public key modulus:" + new String(Hex.encode(publicKey.getModulus().toByteArray()))); //公钥-指数(e1) System.out.println("public key exponent:" + new String(Hex.encode(publicKey.getPublicExponent().toByteArray()))); //JS加密后的字符串 String param = "8c49dfb92a0c8d15b0187b1eabc343a80f340962ebecc497205f83f6a4792141d4e711b6d439388ecf691df4eda2cae1e6431573b61e3f564ffe1c757e32f3e846b5983e5939ddeb28c9570001d7f208ffbaa069677d363cc73e4c78c0d508e8b0b9f6205473269bbfbc22e7fb9413be4c449520eb6cfb4fbbff4e7e189a005a"; //解密后的字符串 String param1 = RSAUtils.decryptStringByJs(param); /*后端的加密和解密-在加密的方法中已经使用了公钥指数和系数*/ try { //加密 byte[] param3 = encrypt("你好> @# !!# #"); //解密 String decrypt = RSAUtils.decrypt(param3); System.out.println(decrypt); } catch (Exception e) { e.printStackTrace(); } } } src/main/java/org/springblade/modules/attendance/controller/AttendanceController.java
@@ -9,6 +9,7 @@ import lombok.AllArgsConstructor; import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.excel.util.ExcelUtil; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Query; import org.springblade.core.tool.api.R; @@ -44,8 +45,6 @@ public class AttendanceController extends BladeController { private final IAttendanceService attendanceService; // private final IEnclosureService iEnclosureService; private final IDictBizService iDictBizService; @@ -83,24 +82,6 @@ IPage<AttendanceVO> pages = attendanceService.selectAttendancePage(Condition.getPage(query), attendance); return R.data(pages); } // /** // * 保安位置比对 // */ // @GetMapping("/positionThan") // public R positionThan(@Valid Attendance attendance, HttpServletResponse response) { // response.setHeader("Access-Control-Allow-Origin", "*"); // response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); // response.setHeader("Access-Control-Allow-Credentials", "true"); // Enclosure enclosure = new Enclosure(); // enclosure.setAnumber(attendance.getNumber()); // //查询当前处警人员的电子围栏信息 // Boolean onArea = iEnclosureService.isOnArea(attendance.getJd(),attendance.getWd(),enclosure); // if (onArea){ // return R.data(true); // } // return R.data(false); // } /** src/main/java/org/springblade/modules/exam/service/impl/ExamScoreServiceImpl.java
@@ -187,7 +187,7 @@ myAsyncService.FTP(s); } //模拟考试 //培训考试 if (paper.getExamType() == 2) { TrainingRegistration trainingRegistration = new TrainingRegistration(); trainingRegistration.setCandidateNo(examScore.getCandidateNo()); @@ -210,7 +210,8 @@ //FtpUtil.sqlFileUpload(s); myAsyncService.FTP(s); } //设置提交时间 examScore.setExamEndTime(new Date()); //设置考试ID examScore.setExamId(examScore.getPapersId().toString()); //设置理论得分 src/main/java/org/springblade/modules/signature/entity/BaseSign.java
@@ -8,7 +8,6 @@ /** * 第三方接口对接密钥 */ @SuppressWarnings("deprecation") @Data public class BaseSign implements Serializable{ src/main/java/org/springblade/modules/signature/interceptor/ExternalAdapter.java
New file @@ -0,0 +1,40 @@ package org.springblade.modules.signature.interceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; /** * 拦截器 * @author zhongrj * @time 2022-03-10 */ @Configuration public class ExternalAdapter extends WebMvcConfigurationSupport { /** * 新增拦截 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ExternalInterceptor()). addPathPatterns("/simulateExamRecord/getSimulateExamRecordInfo", "/simulateExamRecord/pauseExam", "/simulateExamRecord/getSimulateExamRefreshInfo", "/simulateExamRecord/beginExam", "/simulateExamRecord/saveSimulateExam", "/examSubjectChoices/getSubjectResultInfoBySimulate", "/blade-user/getNotUpdatePwdInfo", "/electronRail/**", "/attendance/AppSave" ); super.addInterceptors(registry); } @Bean public ExternalInterceptor getExternalInterceptor(){ return new ExternalInterceptor(); } } src/main/java/org/springblade/modules/signature/interceptor/ExternalInterceptor.java
New file @@ -0,0 +1,50 @@ package org.springblade.modules.signature.interceptor; import org.springblade.modules.signature.util.SignUtil; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 拦截器 * @author zhongrj * @time 2022-3-10 */ @Component public class ExternalInterceptor implements HandlerInterceptor { /** * 拦截所有的设备查询操作,在此之前做更新设备状态的操作 * @param request 请求域 * @param response 响应域 * @param handler 处理器 * @return * @throws Exception 异常 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // String acc = "454sd5fa45dsa5fdaf54"; // //校验签名 // Boolean aBoolean = SignUtil.checkSign(request, acc); // if (aBoolean){ // System.out.println("签名校验通过,放行"); // //放行 // return true; // } // //拒绝访问 // return false; return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } } src/main/java/org/springblade/modules/signature/util/SignUtil.java
New file @@ -0,0 +1,144 @@ package org.springblade.modules.signature.util; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springblade.common.utils.HttpClientUtils; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.util.*; /** * sign 生成工具类 * @author zhongrj * @since 2022-03-11 */ public class SignUtil { private static Logger LOGGER = LoggerFactory.getLogger(SignUtil.class); /** * 获取签名sign * @param params 参数集合不含appSecret * @param secret 验证接口的appSecret * @return */ public static String getSign(Map params,String secret) { String sign=""; StringBuilder sb = new StringBuilder(); //1. 先对请求参数排序 Set<String> keyset=params.keySet(); TreeSet<String> sortSet=new TreeSet<>(); sortSet.addAll(keyset); Iterator<String> it=sortSet.iterator(); //2. 把参数的key value链接起来 ,再把appSecret拼接参数字符串的最后面,得到要加密的字符串 while(it.hasNext()) { String key=it.next(); String value=params.get(key).toString(); sb.append(key).append(value); } sb.append(secret); byte[] md5Digest; try { //3. Md5加密 md5Digest = getMD5Digest(sb.toString()); //4.得到sign sign = byte2hex(md5Digest); } catch (IOException e) { LOGGER.error("生成签名错误",e); } // 5. 返回 sign return sign; } /** * 回调接口验证签名方法 * @param request * @return */ public static Boolean checkSign(HttpServletRequest request,String appSecret){ Boolean flag= false; String sign = request.getParameter("sign");//签名 if(StringUtils.isEmpty(sign)){ return false; } //检查sign是否过期 Enumeration<?> pNames = request.getParameterNames(); Map<String, String> params = new HashMap<>(); while (pNames.hasMoreElements()) { String pName = (String) pNames.nextElement(); if("sign".equals(pName)) { continue; } String pValue = request.getParameter(pName); params.put(pName, pValue); } if(sign.equals(getSign(params, appSecret))){ flag = true; } return flag; } /** * MD5加密数据方法 */ private static byte[] getMD5Digest(String data) throws IOException { byte[] bytes = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); bytes = md.digest(data.getBytes("UTF-8")); } catch (GeneralSecurityException gse) { throw new IOException(gse); } return bytes; } /** * MD5加密数据后的数据处理方法 */ private static String byte2hex(byte[] bytes) { StringBuilder sign = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { sign.append("0"); } sign.append(hex.toUpperCase()); } return sign.toString(); } public static String utf8Encoding(String value, String sourceCharsetName) { try { return new String(value.getBytes(sourceCharsetName), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException(e); } } /** 测试方法 */ public static void main(String[] args) { //参数签名算法测试例子 HashMap<String, String> signMap = new HashMap<String, String>(); String appkey = "584561146"; signMap.put("appKey",appkey); // System.out.println("得到签名sign1:"+getSign(signMap,"454sd5fa45dsa5fdaf54")); String sign = getSign(signMap, "454sd5fa45dsa5fdaf54"); signMap.put("sign",sign); HttpClientUtils.postParams("http://localhost:81/attendance/AppSave", appkey, signMap); } } src/main/java/org/springblade/modules/signature/util/SignUtils.java
@@ -5,6 +5,9 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.qcloud.cos.utils.Md5Utils; import liquibase.util.MD5Util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springblade.common.utils.Md5SignUtil; @@ -14,8 +17,8 @@ /** * 签名验证工具类 * @author Administrator * @since 2022-02-15 * @author arsn * @since 2022-03-10 */ @Slf4j public class SignUtils { @@ -24,7 +27,7 @@ Map<String, Object> map = new HashMap<>(); map.put("sign",sign.getSign()); map.put("accessKeyId",sign.getAccessKeyId()); // map.put("accessDate",sign.getAccessKeyId()); map.put("accessDate",sign.getAccessDate()); return Md5SignUtil.signRequest(map,accessKeySecret); }