企业网站模板源码免费/厦门网站seo哪家好
目录
- 安全性
- 功能介绍
- 实现流程
- 开放平台依赖代码
- AES加解密工具类
- PlatformConfig
- RequestUtils
- PlatformService
- CommonCode
- ZuulFilterHelper
- ServerResponse
- PlatformContact
- RsaSignature
- RsaUtils
- StreamUtil
- 开放平台-解密过滤器
- 开放平台-加密过滤器
- 调用方代码
- 公共代码
- Get-Demo
- Post-Demo
安全性
既然你能看到我这篇文章,就代表你目前或者是你想做或者已经做过接口加解密的功能,做加密的目的一定是为了安全,这是毋庸置疑的。
功能介绍
因为我们要开放我们自己的接口给接入方,所以一些加密和限流是免不了要做的,可以理解为我们要做一个开放平台。
既然要做开放平台,肯定会同时把同一个接口开放给多个接入方,每个接入方的身份标识,私钥、签名都是不一样的。
目前我采用了2种加密方式,一种非对称加密一种是对称加密,非对称加密用于签名,对称加密用于请求体加密和解密,非对称加密采用RSA,对称加密采用AES。
目前接入方的配置都是放置在redis中,但是表已经有设计(没放上来,有需求的,下方评论),后期可以改造成,配置写入表后更新到redis,保证表和缓存一致性。
实现流程
开放平台采用zuul过滤器来实现以下步骤:
- 校验接入方的签名是否正确
- 对请求体进行解密
- 对开放平台返回的响应内容进行加密
- 校验接入方的IP地址是否在白名单内
过滤器依赖工具类较多,不过我都放上来了,可以实现从0到1,主要代码就是2个过滤器
开放平台依赖代码
AES加解密工具类
package com.lwh.utils.encrypt;import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;/*** AES加解密工具类**/
public class AesUtil {/*** 加密* 1.构造密钥生成器* 2.根据ecnodeRules规则初始化密钥生成器* 3.产生密钥* 4.创建和初始化密码器* 5.内容加密* 6.返回字符串*/public static String aesEncode(String content,String pwd) {try {//1.构造密钥生成器,指定为AES算法,不区分大小写KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");//2.根据ecnodeRules规则初始化密钥生成器//生成一个128位的随机源,根据传入的字节数组SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(pwd.getBytes());keyGenerator.init(128, random);//3.产生原始对称密钥SecretKey originalKey = keyGenerator.generateKey();//4.获得原始对称密钥的字节数组byte[] raw = originalKey.getEncoded();//5.根据字节数组生成AES密钥SecretKey key = new SecretKeySpec(raw, "AES");//6.根据指定算法AES自成密码器Cipher cipher = Cipher.getInstance("AES");//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEYcipher.init(Cipher.ENCRYPT_MODE, key);//8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);//9.根据密码器的初始化方式--加密:将数据加密byte[] byteAES = cipher.doFinal(byteEncode);//10.将加密后的数据转换为字符串//这里用Base64Encoder中会找不到包//解决办法://在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。//11.将字符串返回return new BASE64Encoder().encode(byteAES);} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}/*** 解密* 解密过程:* 1.同加密1-4步* 2.将加密后的字符串反纺成byte[]数组* 3.将加密内容解密*/public static String aesDecode(String content,String pwd) {try {//1.构造密钥生成器,指定为AES算法,不区分大小写KeyGenerator keygen = KeyGenerator.getInstance("AES");//2.根据ecnodeRules规则初始化密钥生成器//生成一个128位的随机源,根据传入的字节数组SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(pwd.getBytes());keygen.init(128, random);//3.产生原始对称密钥SecretKey originalKey = keygen.generateKey();//4.获得原始对称密钥的字节数组byte[] raw = originalKey.getEncoded();//5.根据字节数组生成AES密钥SecretKey key = new SecretKeySpec(raw, "AES");//6.根据指定算法AES自成密码器Cipher cipher = Cipher.getInstance("AES");//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEYcipher.init(Cipher.DECRYPT_MODE, key);//8.将加密并编码后的内容解码成字节数组byte[] byteContent = new BASE64Decoder().decodeBuffer(content);/** 解密*/byte[] byteDecode = cipher.doFinal(byteContent);return new String(byteDecode, StandardCharsets.UTF_8);} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {throw new RuntimeException("兄弟,配置文件中的密码需要使用AES加密,请使用com.zheng.common.util.AESUtil工具类修改这些值!");//e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}}
PlatformConfig
package com.lwh.model;import java.io.Serializable;import lombok.Data;@Data
public class PlatformConfig implements Serializable {private static final long serialVersionUID = 4705311536029751175L;/*** 白名单*/private String whiteIpList;/*** 平台提供ras公钥*/private String platformUploadPubRsa;/*** aes密码*/private String aesKey;
}
RequestUtils
/*** 从请求中获取body数据** @param request* @return* @throws Exception*/public static String getBodyString(HttpServletRequest request) throws Exception {request.setCharacterEncoding("UTF-8");String body = null;StringBuilder stringBuilder = new StringBuilder();BufferedReader bufferedReader = null;try {InputStream inputStream = request.getInputStream();if (inputStream != null) {bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));char[] charBuffer = new char[128];int bytesRead = -1;while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {stringBuilder.append(charBuffer, 0, bytesRead);}}} catch (IOException ex) {throw ex;} finally {if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException ex) {throw ex;}}}body = stringBuilder.toString();return body;}/*** 获取ip工具类,除了getRemoteAddr,其他ip均可伪造** @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ip = request.getHeader("Cdn-Src-Ip"); // 网宿cdn的真实ipif (ip == null || ip.length() == 0 || " unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_CLIENT_IP"); // 蓝讯cdn的真实ip}if (ip == null || ip.length() == 0 || " unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Forwarded-For"); // 获取代理ip}if (ip == null || ip.length() == 0 || " unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP"); // 获取代理ip}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP"); // 获取代理ip}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr(); // 获取真实ip}return ip;}/*** 获取head key* @param request* @param key* @return*/public static String getHeadParams(HttpServletRequest request,String key){String token =request.getHeader(key);if (token == null) {token = request.getParameter(key);if(token == null){return null;}}return token.trim();}
PlatformService
package com.lwh.service;import com.lwh.constant.RedisKeyConstant;
import com.lwh.model.PlatformConfig;
import com.lwh.utils.JsonUtil;import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;import lombok.extern.slf4j.Slf4j;@Service
@Slf4j
public class PlatformService {@AutowiredStringRedisTemplate redisTemplate;/*** 根据appId 获取平台信息* @return*/public PlatformConfig getPlatformByAppId(String appId){String redisKey= RedisKeyConstant.Platform.PLATFORM_CONFIG+appId;String json = redisTemplate.opsForValue().get(redisKey);if(StringUtils.isBlank(json)){return null;}else{return JsonUtil.string2Obj(json,PlatformConfig.class);}}
}package com.lwh.constant;public interface RedisKeyConstant {interface Platform {/*** 平台配置,恒久缓存*/String PLATFORM_CONFIG = "PLATFORM_CONFIG_";}}
CommonCode
package com.lwh.response;public enum CommonCode implements ResultCode{//公共部分SUCCESS(200,"成功"),CODE_00001(1001,"系统繁忙,请稍后重试!"),CODE_00002(1002,"参数异常"),CODE_00404(1003,"请求不存在!"),CODE_00405(1004,"验签失败!");CommonCode(Integer code, String msg) {this.code = code;this.msg = msg;}private Integer code;private String msg;@Overridepublic Integer code() {return code;}@Overridepublic String msg() {return msg;}
}
ZuulFilterHelper
package com.lwh.filter;import com.lwh.response.ServerResponse;
import com.lwh.utils.JsonUtil;
import com.netflix.zuul.context.RequestContext;import javax.servlet.http.HttpServletResponse;import lombok.extern.slf4j.Slf4j;/**
* 过滤器访问帮助类
*/
@Slf4j
public class ZuulFilterHelper {/*** 拒绝访问*/public static void accessDenied(ServerResponse serverResponse) {log.error("网关拒绝访问:{}", JsonUtil.obj2StringPretty(serverResponse));RequestContext requestContext = RequestContext.getCurrentContext();//得到responseHttpServletResponse response = requestContext.getResponse();//拒绝访问requestContext.setSendZuulResponse(false);//设置响应代码requestContext.setResponseStatusCode(200);//转成jsonString jsonString = JsonUtil.objectToJson(serverResponse);requestContext.setResponseBody(jsonString);//转成json,设置contentTyperesponse.setContentType("application/json;charset=utf-8");}
}
ServerResponse
package com.lwh.response;import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;import java.io.Serializable;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiModel(value = "服务响应",description = "通用服务响应结果")
public class ServerResponse<T>,Serializable {/*** 成功or失败*/@ApiModelProperty(value = "结果",example = "true")private boolean result;/*** 状态*/@ApiModelProperty(value = "状态码,成功:00000",example = "00000")private Integer code;/*** 描述*/@ApiModelProperty(value = "描述,错误描述",example = "SUCCESS")private String message;private T data;public ServerResponse() {}public ServerResponse(boolean result, Integer code, T data) {this.result = result;this.code = code;this.data = data;}public ServerResponse(Integer code, String message, T data) {this.code = code;this.message = message;this.data = data;}public ServerResponse(boolean result, Integer code, String message, T data) {this.result = result;this.code = code;this.message = message;this.data = data;}public ServerResponse(boolean result, Integer code, String message) {this.result = result;this.code = code;this.message = message;}/*** 使之不在json序列化结果当中* @return*/@JsonIgnorepublic boolean isSuccess() {return result;}public boolean isResult() {return result;}public Integer getCode() {return code;}public T getData() {return data;}public String getMessage() {return message;}public static <T> ServerResponse<T> createBySuccess() {return new ServerResponse<T>(true, CommonCode.SUCCESS.code(), CommonCode.SUCCESS.msg());}public static <T> ServerResponse<T> createBySuccess(T data) {return new ServerResponse<T>(true, CommonCode.SUCCESS.code(), CommonCode.SUCCESS.msg(), data);}public static <T> ServerResponse<T> createBySuccess(String message, T data) {return new ServerResponse<T>(true, CommonCode.SUCCESS.code(), message, data);}public static <T> ServerResponse<T> createByError() {return new ServerResponse<T>(false, CommonCode.CODE_00001.code(), CommonCode.CODE_00001.msg());}public static <T> ServerResponse<T> createByErrorMessage(String message) {return new ServerResponse<T>(false, CommonCode.CODE_00001.code(), message);}public static <T> ServerResponse<T> createByErrorCodeMessage(Integer code, String message) {return new ServerResponse<T>(false, code, message);}public static <T> ServerResponse<T> createErrorByCode(ResultCode statusCode) {return new ServerResponse<T>(false, statusCode.code(), statusCode.msg());}public void setCode(Integer code) {this.code = code;}public void setData(T data) {this.data = data;}public void setMessage(String message) {this.message = message;}@Overridepublic String toString() {return "ServerResponse{" +"result=" + result +", code='" + code + '\'' +", data=" + data +", message='" + message + '\'' +'}';}
}
PlatformContact
package com.lwh.common;public interface PlatformContact {String APP_ID="appId";String VERSION="version";String TIMESTAMP="timestamp";String SIGN="sign";
}
RsaSignature
package com.lwh.utils.encrypt;import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;import org.apache.commons.lang3.StringUtils;/*** RSA、RSA2算法签名*/
public class RsaSignature {private static final String RSA = "RSA";private static final String RSA2 = "RSA2";/*** 获取签名内容** @param sortedParams* @return*/public static String getSignContent(Map<String, String> sortedParams) {StringBuilder content = new StringBuilder();List<String> keys = new ArrayList(sortedParams.keySet());Collections.sort(keys);int index = 0;for (String key : keys) {String value = sortedParams.get(key);if ((StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value))) {content.append(index == 0 ? "" : "&").append(key).append("=").append(value);++index;}}return content.toString();}/*** 根据类型签名** @param content 签名内容* @param privateKey 私钥* @param signType 签名类型RSA、RSA2* @return* @throws RuntimeException*/public static String rsaSign(String content, String privateKey, String signType) throws RuntimeException {if (RSA.equals(signType)) {return rsaSign(content, privateKey);} else if (RSA2.equals(signType)) {return rsa256Sign(content, privateKey);} else {throw new RuntimeException("Sign Type is Not Support : signType=" + signType);}}/*** rsa签名** @param content 签名内容* @param privateKey 私钥* @return* @throws RuntimeException*/public static String rsaSign(String content, String privateKey) throws RuntimeException {try {PrivateKey priKey = RsaUtils.getPrivateKey(privateKey);Signature signature = Signature.getInstance("SHA1WithRSA");signature.initSign(priKey);signature.update(content.getBytes(StandardCharsets.UTF_8));byte[] signed = signature.sign();return new String(Base64.getEncoder().encode(signed));} catch (InvalidKeySpecException var6) {throw new RuntimeException("RSA私钥格式不正确,请检查是否正确配置了PKCS8格式的私钥", var6);} catch (Exception var7) {throw new RuntimeException("RSAContent = " + content + "; charset = " + "UTF-8", var7);}}/*** rsa签名** @param params 参数map* @param privateKey 私钥* @return* @throws RuntimeException*/public static String rsaSign(Map<String, String> params, String privateKey) throws RuntimeException {String signContent = getSignContent(params);return rsaSign(signContent, privateKey);}/*** rsa2签名** @param content 签名内容* @param privateKey 私钥* @return* @throws RuntimeException*/public static String rsa256Sign(String content, String privateKey) throws RuntimeException {try {PrivateKey priKey = RsaUtils.getPrivateKeyFromPKCS8(new ByteArrayInputStream(privateKey.getBytes()));Signature signature = Signature.getInstance("SHA256WithRSA");signature.initSign(priKey);signature.update(content.getBytes(StandardCharsets.UTF_8));byte[] signed = signature.sign();return new String(Base64.getEncoder().encode(signed));} catch (Exception var6) {throw new RuntimeException("RSAContent = " + content + "; charset = " + "UTF-8", var6);}}/*** rsa2签名** @param params 参数map* @param privateKey 私钥* @return* @throws RuntimeException*/public static String rsa256Sign(Map<String, String> params, String privateKey) throws RuntimeException {String signContent = getSignContent(params);return rsa256Sign(signContent, privateKey);}/*** 获取签名内容字符串** @param params 参数map* @return*/public static String getSignCheckContent(Map<String, String> params) {if (params == null) {return null;} else {params.remove("sign");StringBuilder content = new StringBuilder();List<String> keys = new ArrayList(params.keySet());Collections.sort(keys);for (int i = 0; i < keys.size(); ++i) {String key = keys.get(i);String value = params.get(key);content.append(i == 0 ? "" : "&").append(key).append("=").append(value);}return content.toString();}}/*** rsa验签** @param content 验签内容* @param publicKey 公钥* @param sign 签名* @param signType 签名类型RSA/RSA2* @return* @throws RuntimeException*/public static boolean rsaCheck(String content, String publicKey, String sign, String signType) throws RuntimeException {if (RSA.equals(signType)) {return rsaCheck(content, sign, publicKey);} else if (RSA2.equals(signType)) {return rsa256Check(content, sign, publicKey);} else {throw new RuntimeException("Sign Type is Not Support : signType=" + signType);}}/*** rsa验签** @param params 参数map* @param publicKey 公钥* @return* @throws RuntimeException*/public static boolean rsaCheck(Map<String, String> params, String publicKey) throws RuntimeException {String sign = params.get("sign");String content = getSignCheckContent(params);return rsaCheckContent(content, sign, publicKey, "UTF-8");}/*** rsa2验签** @param params* @param publicKey* @return* @throws RuntimeException*/public static boolean rsa256Check(Map<String, String> params, String publicKey) throws RuntimeException {String sign = params.get("sign");String content = getSignCheckContent(params);return rsaCheckContent(content, sign, publicKey, "UTF-8");}/*** rsa验签** @param content* @param sign* @param publicKey* @return* @throws RuntimeException*/public static boolean rsaCheck(String content, String sign, String publicKey) throws RuntimeException {return rsaCheckContent(content, sign, publicKey, "UTF-8");}/*** rsa2验签** @param content* @param sign* @param publicKey* @return* @throws RuntimeException*/public static boolean rsa256Check(String content, String sign, String publicKey) throws RuntimeException {return rsa256CheckContent(content, sign, publicKey, "UTF-8");}/*** rsa验签** @param content* @param sign* @param publicKey* @param charset* @return* @throws RuntimeException*/public static boolean rsaCheckContent(String content, String sign, String publicKey, String charset) throws RuntimeException {try {PublicKey pubKey = RsaUtils.getPublicKey(publicKey);Signature signature = Signature.getInstance("SHA1WithRSA");signature.initVerify(pubKey);if (StringUtils.isEmpty(charset)) {signature.update(content.getBytes());} else {signature.update(content.getBytes(charset));}return signature.verify(Base64.getDecoder().decode(sign.getBytes()));} catch (Exception var6) {throw new RuntimeException("RSAContent = " + content + ",sign=" + sign + ",charset = " + charset, var6);}}/*** rsa2验签** @param content* @param sign 签名* @param publicKey* @param charset* @return* @throws RuntimeException*/public static boolean rsa256CheckContent(String content, String sign, String publicKey, String charset) throws RuntimeException {try {PublicKey pubKey = RsaUtils.getPublicKey(publicKey);Signature signature = Signature.getInstance("SHA256WithRSA");signature.initVerify(pubKey);if (StringUtils.isEmpty(charset)) {signature.update(content.getBytes());} else {signature.update(content.getBytes(charset));}return signature.verify(Base64.getDecoder().decode(sign.getBytes()));} catch (Exception var6) {throw new RuntimeException("RSAContent = " + content + ",sign=" + sign + ",charset = " + charset, var6);}}}
RsaUtils
package com.lwh.utils.encrypt;import com.lwh.utils.StreamUtil;import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;import lombok.extern.slf4j.Slf4j;/*** 读取RSA密钥*/
@Slf4j
public class RsaUtils {private static final String CHARSET = "UTF-8";private static final String SIGN_ALGORITHMS = "SHA1WithRSA";/*** -----------------------------------------私钥读取start----------------------------------------------------*//*** 字符串转私钥** @param keyString BASE64密钥字符串* @return* @throws Exception*/public static PrivateKey getPrivateKey(String keyString) throws Exception {return getPrivateKeyFromPKCS8(new ByteArrayInputStream(keyString.getBytes()));}/*** 根据私钥路径读取BASE64密钥字符串** @param path 私钥路径* @param pwd 私钥密码* @return*/public static String getPrivateKeyStringFromFile(String path, String pwd) {PrivateKey privateKey = getPrivateKeyFromFile(path, pwd);if (privateKey == null) {return null;}return privateKeyToString(privateKey);}/*** 根据私钥路径读取私钥对象** @param path 私钥路径* @param priKeyPass 私钥密码* @return*/public static PrivateKey getPrivateKeyFromFile(String path, String priKeyPass) {InputStream priKeyStream = null;try {priKeyStream = new FileInputStream(path);byte[] reads = new byte[priKeyStream.available()];priKeyStream.read(reads);return getPrivateKeyFromPKCS8(new ByteArrayInputStream(reads));} catch (IOException e) {log.error("解析文件,读取私钥失败:", e);} catch (KeyStoreException e) {log.error("私钥存储异常:", e);} catch (NoSuchAlgorithmException e) {log.error("不存在的解密算法:", e);} catch (CertificateException e) {log.error("证书异常:", e);} catch (UnrecoverableKeyException e) {log.error("不可恢复的秘钥异常", e);} catch (Exception e) {log.error("解析文件,读取私钥失败:", e);} finally {if (priKeyStream != null) {try {priKeyStream.close();} catch (Exception e) {e.printStackTrace();}}}return null;}/*** 流转换密钥** @param ins 密钥流* @return* @throws Exception*/public static PrivateKey getPrivateKeyFromPKCS8(InputStream ins) throws Exception {if (ins != null) {KeyFactory keyFactory = KeyFactory.getInstance("RSA");byte[] encodedKey = StreamUtil.readText(ins).getBytes();encodedKey = Base64.getDecoder().decode(encodedKey);return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));} else {return null;}}public static String privateKeyToString(PrivateKey privateKey) {Base64.Encoder encoder = Base64.getEncoder();byte[] publicKeyString = encoder.encode(privateKey.getEncoded());return new String(publicKeyString);}/*** -----------------------------------------公钥start----------------------------------------------------*//*** 字符串转公钥** @param keyString* @return* @throws Exception*/public static PublicKey getPublicKey(String keyString) throws Exception {Base64.Decoder decoder = Base64.getDecoder();byte[] keyBytes = decoder.decode(keyString);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(EncryptMode.RSA.value());return keyFactory.generatePublic(keySpec);}/*** 指定路径读取公钥BASE64字符串** @param path* @return*/public static String getPublicKeyStringFromFile(String path) {PublicKey publicKey = null;FileInputStream pubKeyStream = null;try {pubKeyStream = new FileInputStream(path);byte[] reads = new byte[pubKeyStream.available()];pubKeyStream.read(reads);publicKey = getPublicKey(new String(reads));} catch (Exception e) {e.printStackTrace();} finally {if (pubKeyStream != null) {try {pubKeyStream.close();} catch (Exception e) {e.printStackTrace();}}}if (publicKey == null) {return null;}return publicKeyToString(publicKey);}/*** 指定路径读取公钥BASE64字符串** @param path* @return*/public static PublicKey getPublicKeyFromFile(String path) {FileInputStream pubKeyStream = null;try {pubKeyStream = new FileInputStream(path);byte[] reads = new byte[pubKeyStream.available()];pubKeyStream.read(reads);return getPublicKeyFromX509(new ByteArrayInputStream(reads));} catch (Exception e) {e.printStackTrace();} finally {if (pubKeyStream != null) {try {pubKeyStream.close();} catch (Exception e) {e.printStackTrace();}}}return null;}public static PublicKey getPublicKeyFromX509(InputStream ins) throws Exception {KeyFactory keyFactory = KeyFactory.getInstance("RSA");StringWriter writer = new StringWriter();StreamUtil.io(new InputStreamReader(ins), writer);byte[] encodedKey = writer.toString().getBytes();encodedKey = Base64.getDecoder().decode(encodedKey);return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));}public static String publicKeyToString(PublicKey publicKey) {Base64.Encoder encoder = Base64.getEncoder();byte[] publicKeyString = encoder.encode(publicKey.getEncoded());return new String(publicKeyString);}/*** RSA验签名检查** @param content 待签名数据* @param sign 签名值* @param public_key 公钥* @return 布尔值*/public static boolean verify(String content, String sign, String public_key) {try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");byte[] encodedKey = org.apache.commons.codec.binary.Base64.decodeBase64(public_key);PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));Signature signature = Signature.getInstance(SIGN_ALGORITHMS);signature.initVerify(pubKey);signature.update(content.getBytes(CHARSET));return signature.verify(org.apache.commons.codec.binary.Base64.decodeBase64(sign));} catch (Exception e) {throw new RuntimeException("验签时遇到异常", e);}}}
StreamUtil
package com.lwh.utils;import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;public class StreamUtil {private static final int DEFAULT_BUFFER_SIZE = 8192;public StreamUtil() {}public static void io(InputStream in, OutputStream out) throws IOException {io((InputStream) in, (OutputStream) out, -1);}public static void io(InputStream in, OutputStream out, int bufferSize) throws IOException {if (bufferSize == -1) {bufferSize = 8192;}byte[] buffer = new byte[bufferSize];int amount;while ((amount = in.read(buffer)) >= 0) {out.write(buffer, 0, amount);}}public static void io(Reader in, Writer out) throws IOException {io((Reader) in, (Writer) out, -1);}public static void io(Reader in, Writer out, int bufferSize) throws IOException {if (bufferSize == -1) {bufferSize = 4096;}char[] buffer = new char[bufferSize];int amount;while ((amount = in.read(buffer)) >= 0) {out.write(buffer, 0, amount);}}public static OutputStream synchronizedOutputStream(OutputStream out) {return new StreamUtil.SynchronizedOutputStream(out);}public static OutputStream synchronizedOutputStream(OutputStream out, Object lock) {return new StreamUtil.SynchronizedOutputStream(out, lock);}public static String readText(InputStream in) throws IOException {return readText(in, (String) null, -1);}public static String readText(InputStream in, String encoding) throws IOException {return readText(in, encoding, -1);}public static String readText(InputStream in, String encoding, int bufferSize) throws IOException {Reader reader = encoding == null ? new InputStreamReader(in) : new InputStreamReader(in, encoding);return readText(reader, bufferSize);}public static String readText(Reader reader) throws IOException {return readText(reader, -1);}public static String readText(Reader reader, int bufferSize) throws IOException {StringWriter writer = new StringWriter();io((Reader) reader, (Writer) writer, bufferSize);return writer.toString();}private static class SynchronizedOutputStream extends OutputStream {private OutputStream out;private Object lock;SynchronizedOutputStream(OutputStream out) {this(out, out);}SynchronizedOutputStream(OutputStream out, Object lock) {this.out = out;this.lock = lock;}@Overridepublic void write(int datum) throws IOException {Object var2 = this.lock;synchronized (this.lock) {this.out.write(datum);}}@Overridepublic void write(byte[] data) throws IOException {Object var2 = this.lock;synchronized (this.lock) {this.out.write(data);}}@Overridepublic void write(byte[] data, int offset, int length) throws IOException {Object var4 = this.lock;synchronized (this.lock) {this.out.write(data, offset, length);}}@Overridepublic void flush() throws IOException {Object var1 = this.lock;synchronized (this.lock) {this.out.flush();}}@Overridepublic void close() throws IOException {Object var1 = this.lock;synchronized (this.lock) {this.out.close();}}}public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {Set<Object> seen = ConcurrentHashMap.newKeySet();return t -> seen.add(keyExtractor.apply(t));}}
开放平台-解密过滤器
package com.lwh.filter.zrs;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lwh.common.PlatformContact;
import com.lwh.filter.ZuulFilterHelper;
import com.lwh.model.PlatformConfig;
import com.lwh.response.CommonCode;
import com.lwh.response.ServerResponse;
import com.lwh.service.PlatformService;
import com.lwh.utils.RequestUtil;
import com.lwh.utils.encrypt.AesUtil;
import com.lwh.utils.encrypt.RsaSignature;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import com.zcckj.common.utils.JsonUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.WebUtils;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** @description 开放接口验签解密过滤器*/
@Slf4j
@Component
public class ZrsOpenApiDecryptFilter extends ZuulFilter {@Value("${openapi.uri.prefix}")private String openApiPrefix;@Value("${system.ip.whiteList}")private String systemIpWhiteList;@Autowiredprivate PlatformService platformService;@Overridepublic String filterType() {/*pre:请求在被路由之前执行routing:在路由请求时调用post:在routing和error过滤器之后调用error:处理请求时发生错误调用*/return "pre";}@Overridepublic int filterOrder() {/*过虑器序号,越小越被优先执行*/return 1;}@SneakyThrows@Overridepublic boolean shouldFilter() {//返回true表示要执行此过虑器RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();//需要转换uri的条件,String requestURI = request.getRequestURI();String[] uriArray = openApiPrefix.split(",");for (String anUriArray : uriArray) {if (requestURI.startsWith(anUriArray)) {//后续根据此条件判断是否加密响应与是否重置路由映射log.info("请求地址:{} 是开放接口", requestURI);requestContext.set("isOpenApi", true);return true;}}requestContext.set("isOpenApi", false);return false;}@Overridepublic Object run() throws ZuulException {try {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletRequest request = requestContext.getRequest();//1解析请求参数String appId = RequestUtil.getHeadParams(request, PlatformContact.APP_ID);if (StringUtils.isBlank(appId)) {ZuulFilterHelper.accessDenied(ServerResponse.createByErrorCodeMessage(CommonCode.CODE_00405.code(), "appId不能为空"));return null;}//3查询平台信息PlatformConfig platformConfig =platformService.getPlatformByAppId(appId);if(platformConfig==null){ZuulFilterHelper.accessDenied(ServerResponse.createByErrorCodeMessage(CommonCode.CODE_00405.code(),"非法appId"));return null;}requestContext.set("platformConfigDTO", platformConfig);//4白名单验证/* if (!this.checkWhiteIpList(RequestUtil.getIpAddr(request), platformConfig)) {ZuulFilterHelper.accessDenied(ServerResponse.createByErrorCodeMessage(CommonCode.CODE_00405.code(),"白名单拦截"));return null;}*///5验签if (!this.verifySign(request, platformConfig)) {ZuulFilterHelper.accessDenied(ServerResponse.createByErrorCodeMessage(CommonCode.CODE_00405.code(),"签名失败"));return null;}//文件上传特殊处理,不进行解密了String contentType = request.getHeader("Content-Type");if(!StringUtils.isBlank(contentType)&&contentType.contains("multipart/form-data")){return null;}//请求体不为空不校验String bodyString = RequestUtil.getBodyString(request);JSONObject jsonObject=null;if(StringUtils.isBlank(bodyString)){jsonObject=new JSONObject();}else{//6解密String jsonData = this.decryptData(bodyString, platformConfig);jsonObject = JSON.parseObject(jsonData);}//增加jsonjsonObject.put("distributorId", platformConfig.getDistributorId());String dataContent= JsonUtils.toJsonString(jsonObject);if (StringUtils.isBlank(dataContent)) {ZuulFilterHelper.accessDenied(ServerResponse.createByErrorCodeMessage(CommonCode.CODE_00405.code(),"请求参数解密失败"));return null;}log.info("解密成功后请求参数:{}", dataContent);//7重置请求上下文requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) {@Overridepublic ServletInputStream getInputStream() {return new ServletInputStreamWrapper(dataContent.getBytes());}@Overridepublic int getContentLength() {return dataContent.getBytes().length;}@Overridepublic long getContentLengthLong() {return dataContent.getBytes().length;}});} catch (Exception e) {ZuulFilterHelper.accessDenied(ServerResponse.createErrorByCode(CommonCode.CODE_00001));e.printStackTrace();log.error("ZRS解密验签流程出现异常",e);}return null;}private JSONObject parse(HttpServletRequest request) {JSONObject jsonObject = null;try {//转换参数String res = RequestUtil.getBodyString(request);jsonObject = JSON.parseObject(res);} catch (Exception e) {log.error("服务网关请求参数解析异常", e);return null;}return jsonObject;}/*** 校验请求地址是否符合白名单** @param ip* @param platformConfig* @return*/private boolean checkWhiteIpList(String ip, PlatformConfig platformConfig) {//判断是否 生产环境||测试环境List<String> ipArray = new ArrayList<>();//平台配置白名单if (platformConfig != null) {String ipArrayStr = platformConfig.getWhiteIpList();if (StringUtils.isBlank(ipArrayStr) || StringUtils.isBlank(ip)) {return false;}List<String> ips = Arrays.asList(ipArrayStr.split(","));ipArray.addAll(ips);}//系统配置白名单if (!StringUtils.isBlank(systemIpWhiteList)) {List<String> ips = Arrays.asList(systemIpWhiteList.split(","));ipArray.addAll(ips);}log.info("当前请求ip:{},构建白名单地址列表:{}",ip, ipArray);boolean contains = ipArray.contains(ip);if (!contains) {log.error("请求地址:{},未加入到白名单列表,请求拒绝", ip);return false;}return true;}/*** 使用对接方的DSA公钥进行验签** @param request 请求上下文* @param platformConfig 平台配置* @return* @throws* @author 房维超* @date 2018/10/24 16:07*/private boolean verifySign(HttpServletRequest request, PlatformConfig platformConfig) {//1获取对方公钥String dsaPublicKeyStr = platformConfig.getPlatformUploadPubRsa();StringBuilder originalSign = new StringBuilder();originalSign.append(RequestUtil.getHeadParams(request,PlatformContact.APP_ID));originalSign.append(RequestUtil.getHeadParams(request,PlatformContact.VERSION));originalSign.append(RequestUtil.getHeadParams(request,PlatformContact.TIMESTAMP));String sign = RequestUtil.getHeadParams(request,PlatformContact.SIGN);try {if (!RsaSignature.rsaCheck(originalSign.toString(), sign,dsaPublicKeyStr)) {//签名验证失败return false;}} catch (Exception e) {log.error("网关延签异常", e);return false;}log.info("验证签名成功:{}", originalSign);return true;}/*** 使用我方平台RSA私钥进行解密** @param dataContent 密文数据* @return 解密后的数据* @throws* @author 房维超* @date 2018/10/24 16:14*/private String decryptData(String dataContent, PlatformConfig platformConfig) {try {//1应用私钥String aesKey = platformConfig.getAesKey();log.info("密码:"+aesKey);//2使用私钥解密dataContent = AesUtil.aesDecode(URLDecoder.decode(dataContent, "UTF-8"), aesKey);} catch (Exception e) {log.error("解密请求数据发生异常,报文:{} 错误信息:{},",dataContent, e.getMessage(), e);return null;}return dataContent;}/*** 打印请求参数** @param request*/private String getRequestBody(ContentCachingRequestWrapper request) {ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);if (wrapper != null) {byte[] buf = wrapper.getContentAsByteArray();if (buf.length > 0) {String payload;try {payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());} catch (UnsupportedEncodingException e) {payload = "[unknown]";}return payload.replaceAll("\\n", "");}}return "";}
}
开放平台-加密过滤器
package com.lwh.filter.zrs;import com.lwh.model.PlatformConfig;
import com.lwh.loancloud.response.ServerResponse;
import com.lwh.loancloud.utils.JsonUtil;
import com.lwh.loancloud.utils.encrypt.AesUtil;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;/*** @description 开放接口响应加密过滤器*/
@Slf4j
@Component
public class ZrsOpenApiEncryptFilter extends ZuulFilter {@Autowiredprivate RedisTemplate redisTemplate;@Value("${openapi.uri.prefix}")private String openApiPrefix;@Overridepublic String filterType() {/*pre:请求在被路由之前执行routing:在路由请求时调用post:在routing和error过滤器之后调用error:处理请求时发生错误调用*/return "post";}@Overridepublic int filterOrder() {/*过虑器序号,越小越被优先执行*/return 0;}@Overridepublic boolean shouldFilter() {//返回true表示要执行此过虑器RequestContext requestContext = RequestContext.getCurrentContext();return (boolean) requestContext.get("isOpenApi");}@Overridepublic Object run() throws ZuulException {try {RequestContext requestContext = RequestContext.getCurrentContext();HttpServletResponse response = requestContext.getResponse();response.setContentType("application/json;charset=utf-8");InputStream stream = requestContext.getResponseDataStream();if (stream == null) {log.error("网关加密处理失败,响应数据为空");return null;}String responseContent = StreamUtils.copyToString(stream, StandardCharsets.UTF_8);log.info("网关加密处理,返回值:{}", responseContent);PlatformConfig platformConfig = (PlatformConfig) requestContext.get("platformConfigDTO");ServerResponse serverResponse = JsonUtil.jsonToPojo(responseContent, ServerResponse.class);if (serverResponse == null) {log.error("网关加密处理失败,反序列化ServerResponse失败,内容:{}", requestContext);return null;}if (serverResponse.getData() != null) {//加密处理this.encrypt(serverResponse, platformConfig);}//设置响应代码requestContext.setResponseStatusCode(200);//转成jsonString jsonString = JsonUtil.objectToJson(serverResponse);requestContext.setResponseBody(jsonString);} catch (Exception e) {e.printStackTrace();log.error("ZRS响应加密流程出现异常",e);}return null;}/*** 组装返回数据** @param serverResponse 请求需要的返回数据* @param platformConfig 请求用于的相关配置* @return*/private ServerResponse encrypt(ServerResponse serverResponse, PlatformConfig platformConfig) {try {//使用aes加密String key = platformConfig.getAesKey();String data = JsonUtil.obj2StringPretty(serverResponse.getData());serverResponse.setData(AesUtil.aesEncode(data,key));return serverResponse;} catch (Exception e) {log.error("加密响应数据发生异常:{}", e.getMessage(), e);}return null;}}
调用方代码
公共代码
/*** 生成签名** @param content* @param privateKey* @return* @throws RuntimeException*/public static String rsaSign(String content, String privateKey) throws RuntimeException {try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");byte[] encodedKey = Base64.getDecoder().decode(privateKey.getBytes());PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));Signature signature = Signature.getInstance("SHA1WithRSA");signature.initSign(priKey);signature.update(content.getBytes(StandardCharsets.UTF_8));byte[] signed = signature.sign();return new String(Base64.getEncoder().encode(signed));} catch (InvalidKeySpecException var6) {throw new RuntimeException("RSA私钥格式不正确,请检查是否正确配置了PKCS8格式的私钥", var6);} catch (Exception var7) {throw new RuntimeException("RSAContent = " + content + "; charset = " + "UTF-8", var7);}}/*** 加密* 1.构造密钥生成器* 2.根据ecnodeRules规则初始化密钥生成器* 3.产生密钥* 4.创建和初始化密码器* 5.内容加密* 6.返回字符串*/public static String aesEncode(String content, String pwd) {try {//1.构造密钥生成器,指定为AES算法,不区分大小写KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");//2.根据ecnodeRules规则初始化密钥生成器//生成一个128位的随机源,根据传入的字节数组SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(pwd.getBytes());keyGenerator.init(128, random);//3.产生原始对称密钥SecretKey originalKey = keyGenerator.generateKey();//4.获得原始对称密钥的字节数组byte[] raw = originalKey.getEncoded();//5.根据字节数组生成AES密钥SecretKey key = new SecretKeySpec(raw, "AES");//6.根据指定算法AES自成密码器Cipher cipher = Cipher.getInstance("AES");//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEYcipher.init(Cipher.ENCRYPT_MODE, key);//8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);//9.根据密码器的初始化方式--加密:将数据加密byte[] byteAES = cipher.doFinal(byteEncode);//10.将加密后的数据转换为字符串//这里用Base64Encoder中会找不到包//解决办法://在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。//11.将字符串返回return new BASE64Encoder().encode(byteAES);} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}/*** 解密* 解密过程:* 1.同加密1-4步* 2.将加密后的字符串反纺成byte[]数组* 3.将加密内容解密*/public static String aesDecode(String content, String pwd) {try {//1.构造密钥生成器,指定为AES算法,不区分大小写KeyGenerator keygen = KeyGenerator.getInstance("AES");//2.根据ecnodeRules规则初始化密钥生成器//生成一个128位的随机源,根据传入的字节数组SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(pwd.getBytes());keygen.init(128, random);//3.产生原始对称密钥SecretKey originalKey = keygen.generateKey();//4.获得原始对称密钥的字节数组byte[] raw = originalKey.getEncoded();//5.根据字节数组生成AES密钥SecretKey key = new SecretKeySpec(raw, "AES");//6.根据指定算法AES自成密码器Cipher cipher = Cipher.getInstance("AES");//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEYcipher.init(Cipher.DECRYPT_MODE, key);//8.将加密并编码后的内容解码成字节数组byte[] byteContent = new BASE64Decoder().decodeBuffer(content);/** 解密*/byte[] byteDecode = cipher.doFinal(byteContent);return new String(byteDecode, StandardCharsets.UTF_8);} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {throw new RuntimeException("兄弟,配置文件中的密码需要使用AES加密,请使用com.zheng.common.util.AESUtil工具类修改这些值!");//e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}//异常返nullreturn null;}
Get-Demo
package com.example.demo.open;import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.example.demo.entity.Result;
import com.google.common.collect.Maps;
import sun.misc.BASE64Decoder;import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;/*** @author lwh* @date 2023/2/14* @description 调用开放平台接口**/
public class OpenGetDemo {// 密钥(aes)private static final String secretKey = "";// 私钥private static final String privateKey = "";// 接入方身份标识private static final String appId = "";// 目前版本号private static final String version = "";public static void main(String[] args) {getRequest();}private static void getRequest() {String url = "域名"HttpRequest httpRequest = HttpUtil.createGet(url+"地址");// 时间戳String timestamp = String.valueOf(DateUtil.current());// 签名String sign = rsaSign(appId + version + timestamp, privateKey);HashMap<String, String> maps = Maps.newHashMap();maps.put("appId", appId);maps.put("version", version);maps.put("timestamp", timestamp);maps.put("sign", sign);httpRequest.addHeaders(maps);HashMap<String, String> parameterMap = Maps.newHashMap();parameterMap.put("key", "传入的内容是什么返回的就是什么");httpRequest.formStr(parameterMap);HttpResponse execute = httpRequest.execute();System.out.println("===========================================================返回的内容==========================================================");System.out.println(execute.body());Result result = JSON.parseObject(execute.body(), Result.class);System.out.println("aes解密:" + aesDecode((String) result.getData(), secretKey));}
}
Post-Demo
package com.example.demo.open;import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.example.demo.entity.PostTestRecordRequest;
import com.example.demo.entity.Result;
import com.example.demo.utils.AesUtil;
import com.google.common.collect.Maps;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;/*** @author lwh* @date 2023/2/14* @description 调用开放平台接口**/
public class OpenPostDemo {// 密钥(aes)private static final String secretKey = "";// 私钥private static final String privateKey = "";// 接入方身份标识private static final String appId = "";// 目前版本号private static final String version = "";public static void main(String[] args) throws UnsupportedEncodingException {postRequest();}private static void postRequest() throws UnsupportedEncodingException {String url = "域名"HttpRequest httpRequest = HttpUtil.createPost(url+"地址");// 时间戳String timestamp = String.valueOf(DateUtil.current());// 签名String sign = rsaSign(appId + version + timestamp, privateKey);HashMap<String, String> maps = Maps.newHashMap();maps.put("appId", appId);maps.put("version", version);maps.put("timestamp", timestamp);maps.put("sign", sign);httpRequest.addHeaders(maps);// body加密之后要设置content-typehttpRequest.header("content-type", "application/json");PostTestRecordRequest request = new PostTestRecordRequest();request.setName("xxx");request.setSize(10);request.setAmount(new BigDecimal(100.25));request.setIdList(Arrays.asList(1L, 2L, 3L));String jsonBody = JSON.toJSONString(request);// json加密String content = aesEncode(jsonBody, secretKey);// 加密之后要URL编码,否则传输会出现乱码String encode = URLEncoder.encode(content, "UTF-8");httpRequest.body(encode);System.out.println("请求加密Encode:" + encode);HttpResponse execute = httpRequest.execute();System.out.println("===========================================================返回的内容==========================================================");System.out.println(execute.body());Result result = JSON.parseObject(execute.body(), Result.class);System.out.println("aes解密:" + aesDecode((String) result.getData(), secretKey));}
}
到这双方请求数据和响应数据的加密和解密就完成了,能看出还是有很多东西的,但是毕竟包含了所有东西,你这基本拿过去就能用了,对吧,在做加密和解密的同时也做了接口的限流,后面把接口的限流发布上来供大家参考。
相关文章:

开放平台如何做接口的签名和加解密?
目录安全性功能介绍实现流程开放平台依赖代码AES加解密工具类PlatformConfigRequestUtilsPlatformServiceCommonCodeZuulFilterHelperServerResponsePlatformContactRsaSignatureRsaUtilsStreamUtil开放平台-解密过滤器开放平台-加密过滤器调用方代码公共代码Get-DemoPost-Demo…...

Mr. Cappuccino的第40杯咖啡——Kubernetes之Pod生命周期
Kubernetes之Pod生命周期Pod生命周期官方文档Pod的状态初始化容器案例钩子函数Exec命令TCPSocketHTTPGet案例容器探测Exec命令TCPSocketHTTPGet探测时间重启策略Pod生命周期官方文档 Pod生命周期官方文档 Pod的状态 pending:挂起,apiserver创建了pod资…...

记一次OOM
1,问题描述: 新上了一版代码之后,上游服务请求我们服务失败,报错:“服务不可用”,发现注册中心上服务掉线,查询日志:发现oom:Java heap space,GC overhead limit exceeded。 容易…...

idea插件生成dao类service类controller类以及mapper.xml
idea插件生成dao类service类controller类以及mapper.xml 安装插件Easycode和MybatisX,不用自己写代码 1.Files——》Settings——》Plugins,分别搜索Easycode和MybatisX,点击下载。 2.新建一个springboot模板,选择的依赖如下 3.…...

DML 数据操作语言
概述 DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增、删、改操作。 添加数据(INSERT)修改数据(UPDATE)删除数据(DELETE) 添加数据 1、给指定字段…...

PySpark实战一之入门
1、PySpark的编程模型 分三个模块: 数据输入:通过SparkContext对象,完成数据输入 数据处理计算:输入数据后得到RDD对象,对RDD对象的成员方法进行迭代计算 数据输出:最后通过RDD对象的成员方法࿰…...

【DockerCE】Docker-CE 23.0.1正式版发布
很意外啊!Docker社区版竟然直接从20.xx.xx版本,升级到23.xx.xx版本了。官网地址(For RHEL/CentOS 7.9):https://download.docker.com/linux/centos/7/x86_64/stable/Packages/23.0.1版本官方安装包如下:# l…...

vscode开发的Vue家用电器维修服务系统nodejs+mysql
主要功能包括管理员:首页、个人中心、用户管理、维修员管理、维修信息管理、维修申请管理、维修处理管理、家电类别管理、配件信息管理、配件领用管理、维修结果管理、家电维修知识管理、公告信息管理、留言板管理,用户:首页、个人中心、维修…...

PyQt5数据库开发1 4.2 配置SQL Server 2008 数据源(ODBC编程)
文章目录 配置SQL Server 2008 数据源(ODBC编程) 1. 了解要配置的数据源服务器名称,以及数据库和对应表 2. 打开控制面板,点击管理工具 3. 双击数据源 4. 选择“用户DSN”选项卡,点击“添加” 5. 选择SQL Serv…...

【JavaEE】多线程代码实例:单例模式与阻塞队列BlockingQueue
目录 单例模式: 什么是单例模式? 单例模式的实现方式: 饿汉模式: 懒汉模式: 基于并发编程对单例模式线程安全问题的讨论: 阻塞队列: 标准库中的阻塞队列: 自实现阻塞…...

算法思想 - 搜索算法
本文主要介绍算法中搜索算法的思想,主要包含BFS,DFS。搜索相关题目深度优先搜索和广度优先搜索广泛运用于树和图中,但是它们的应用远远不止如此。BFS广度优先搜索的搜索过程有点像一层一层地进行遍历,每层遍历都以上一层遍历的结果…...

C#底层库--日期扩展类(上周、本周、明年、前年等)
系列文章 C#底层库–记录日志帮助类 本文链接:https://blog.csdn.net/youcheng_ge/article/details/124187709 C#底层库–数据库访问帮助类(MySQL版) 本文链接:https://blog.csdn.net/youcheng_ge/article/details/126886379 …...

如何在 Webpack 中开启图片压缩
工具对比 npmtrends.com/image-minim… 这四个压缩工具,从下载量来看,image-webpack-loader 较多,image-minimizer-webpack-plugin、imagemin-webpack-plugin 次之,imagemin-webpack 已经不再维护,因此不考虑此工具。 …...

Web-Filter
## 今日内容 1. Filter:过滤器 2. Listener:监听器 # Filter:过滤器 1. 概念: * 生活中的过滤器:净水器,空气净化器,土匪、 * web中的过滤器:当访问服务器的资源时…...

测试写文章自动保存
近日恰逢双十一,瞅了瞅自己干瘪的钱包,没忍心入手期待已久的 macPro,只好在虚拟机里玩一下 mac好了,等以后钱包傲气的时候再来个真实的。 安装环境: windows10 VMWare14.2 2018-7-28 小嘚瑟补充:唧唧歪歪大半年,一夜回到解放前,终于剁手整了个真机,可以折腾一下了 ——…...

云平台搭建实例
嗨嗨,每天一更是不是很奈斯?我也觉得,昨天晚上我学校的老师借一天一千的设备,只能用七天,所以我拿出来给你们没有设备和刚用设备的看看吧。操作:首先我们将云平台安装好后,插上网线,…...

【Airplay_BCT】关于Bonjour的概念解答
1.什么是Bonjour? Bonjour,也称为零配置网络,可以自动发现 IP 网络上的计算机、设备和服务。 Bonjour 使用行业标准 IP 协议,允许设备自动发现彼此,无需输入 IP 地址或配置 DNS 服务器。具体来说,Bonjour …...

C++深入浅出(九)—— 多态
文章目录1. 多态的概念2. 多态的定义及实现🍑 多态的构成条件🍑 虚函数🍑 虚函数的重写🍑 虚函数重写的两个例外🍑 C11的override 和 final🍑 重载、覆盖(重写)、隐藏(重定义)的对比3. 抽象类🍑…...

shell学习4
目录 一、统计文本中的词频 二、压缩javascript 三、打印文件的或行中的第n个单词或列---awk 3.1 利用awk打印文件中每行中的第五个单词。 3.2 利用awk打印当前目录下的文件的权限和文件名 3.3 利用awk打印从M行到N行这个范围内的所有文本 3.4 利用awk 部分提取文件中的内…...

VR全景行业的应用价值如何呈现?
互联网高速发展的今天,多媒体所包含的种类也是越来越多,而一些较为传统的表现方式已经越来越无法满足大部分客户对展示方式的要求。而在传统的表现方式中,展现的方式无非是静态的平面图片以及动态的视频,但是他们都有一个缺点就是…...

ESP-IDF:TCP多线程并发服务器
核心代码: 核心思想就是主线程只处理socket监听功能,把数据处理部分分配到不同的线程中去处理。来了一个客户端连接,就分配新的线程去处理该客户端的数据请求。 代码: /多线程并发服务器/ #include <stdio.h> #include …...

Springboot扩展点之SmartInitializingSingleton
前言这篇文章会重点分析一下SmartInitializingSingleton扩展点的功能 特性、实现方式 、工作原理。SmartInitializingSingleton扩展点内只有一个扩展方法,且执行时机在Spring Bean的生命周期里比较靠后,很重要,但是也很简单。功能特性1、Smar…...

基于linux内核的驱动开发学习
1 驱动 定义:驱使硬件动起来的程序 种类:裸机驱动:需求分析--》查原理图--》查芯片手册--》code 系统驱动:需求分析--》查原理图--》查芯片手册--》设备树--》code --》安装到内核中…...

python3 django gunicorn
首先,Gunicorn是一个高效的Web服务器,地位相当于Java中的Tomcat。简单来说gunicorn封装了HTTP的底层实现,我们通过gunicorn启动服务,用户请求与服务相应都经过gunicorn传输。下载gunicorn的方法也比较简单,在django工程…...

专家分享 | 租赁型售楼处标准化示范区提效研究
2023年2月8日上午,优积科技邀请原金地集团北京公司 高级室内设计专业应锎经理为我司团队分享《租赁型售楼处标准化示范区提效》的专题。 此次专家分享课题加上大家踊跃讨论时间长达3小时,会上应总详细介绍了租赁型售楼处标准化示范区提效,需…...

linux之echo使用技巧
参考文章:linux基本功系列-echo命令实战一、echo 命令是什么?作用: echo命令能将指定文本显示在Linux命令行上,或者通过重定向符写入到指定的文件中。语 法:echo [-ne][字符串] / echo [–help][–version]补充说明&am…...

Keras实例教程(7)之构建模型的第三种方式
多年以前,在TensorFlow中搭建深度学习模型对于很多人来说其实仍然是比较困难的。相比之下,Keras作为独立于TensorFlow的一种深度学习框架则要简单很多。在TensorFlow与PyTorch的竞争中逐渐式微的情况下,TensorFlow团队终于宣布Keras将成为在tensorflow2.0中构建和训练模型的…...

【JUC并发编程】18 CopyOnWriteArrayList源码也就够看2分钟
文章目录1、CopyOnWriteArrayList概述2、原理 / 源码1)构造函数2、add()3)get()4)remove()5)iterator()1、CopyOnWriteArrayList概述 CopyOnWriteArrayList相当于线程安全的ArrayList,底层是一个可变数组。 特点如下…...

如何优雅的实现回调函数?
本篇文章又是一期优雅的代码编程介绍———回调函数。 传统的nodejs编程都是这样的 const fs require(fs) fs.readFile(test.txt,utf8, function(err, dataStr){if(err){} }) 嵌套层级如果多了就成回调地狱了。如果我们将这种风格的代码转换成这样呢? const fs …...

3GPP-NR Band20标准定义频点和信道(3GPP V17.7.0 (2022-12))
Reference test frequencies for NR operating band n20 Table 4.3.1.1.1.20-1: Test frequencies for NRoperating band n20 and SCS 15 kHz CBW [MHz]carrierBandwidth...