目录

  • 安全性
  • 功能介绍
  • 实现流程
  • 开放平台依赖代码
    • AES加解密工具类
    • PlatformConfig
    • RequestUtils
    • PlatformService
    • CommonCode
    • ZuulFilterHelper
    • ServerResponse
    • PlatformContact
    • RsaSignature
    • RsaUtils
    • StreamUtil
  • 开放平台-解密过滤器
  • 开放平台-加密过滤器
  • 调用方代码
    • 公共代码
    • Get-Demo
    • Post-Demo

安全性

既然你能看到我这篇文章,就代表你目前或者是你想做或者已经做过接口加解密的功能,做加密的目的一定是为了安全,这是毋庸置疑的。

功能介绍

因为我们要开放我们自己的接口给接入方,所以一些加密和限流是免不了要做的,可以理解为我们要做一个开放平台。

既然要做开放平台,肯定会同时把同一个接口开放给多个接入方,每个接入方的身份标识,私钥、签名都是不一样的。

目前我采用了2种加密方式,一种非对称加密一种是对称加密,非对称加密用于签名,对称加密用于请求体加密和解密,非对称加密采用RSA,对称加密采用AES。

目前接入方的配置都是放置在redis中,但是表已经有设计(没放上来,有需求的,下方评论),后期可以改造成,配置写入表后更新到redis,保证表和缓存一致性。

实现流程

开放平台采用zuul过滤器来实现以下步骤:

  1. 校验接入方的签名是否正确
  2. 对请求体进行解密
  3. 对开放平台返回的响应内容进行加密
  4. 校验接入方的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));}
}

到这双方请求数据和响应数据的加密和解密就完成了,能看出还是有很多东西的,但是毕竟包含了所有东西,你这基本拿过去就能用了,对吧,在做加密和解密的同时也做了接口的限流,后面把接口的限流发布上来供大家参考。

开放平台如何做接口的签名和加解密?相关推荐

  1. 科大讯飞开放平台——语音听写接口的使用

    科大讯飞开放平台--语音听写接口的使用 最近一个项目要用到一个语音识别的功能,主要目的是把用户说的话转换成文字,然后再做其他处理.找了多个语音识别的第三方SDK,比如百度语音识别.微信语音识别.科大讯 ...

  2. 某汽车社区App 签名和加解密分析 (二) : Frida Dump so

    一.目标 App安全的主战场在Native层,分析Native层的so,最趁手的兵器就是Frida和Unidbg了. 今天我们的目标是 某汽车社区App v8.0.1 so 的分析. 二.步骤 特征字 ...

  3. 开放平台设计之接口签名认证

    目录 前言 签名认证 签名认证步骤: 下面以java代码举例: DEMO 前言 当前时代,数据是王 道!当我们自己的平台有了足够大的数据量,就有可能诞生一个开放平台供第三方分析.使用.那么我们怎么去实 ...

  4. 支付宝开放平台当面付接口整体解析

    开放平台基础技术文档:https://doc.open.alipay.com/doc2/detail.htm?treeId=115&articleId=104103&docType=1 ...

  5. 微信开放平台分享功能的app签名怎么获取

    微信开放平台需要的签名如果直接使用eclipse打包生成的MD5签名是不行的. 需要把这个eclipse打包生成MD5签名做一些处理: (1)冒号:去掉 (2)大写字母换成小写字母 (做以上处理的时候 ...

  6. uniApp APP端 支付/分享 微信开放平台的Android 包名签名的坑

    在开放平台配置好包名和签名后是会"立即生效" 网上看2种解决方法能立即生效 1.微信重新登录 2.卸载微信重新安装 原因:当你在你的APP上使用微信登录/分享/支付等,微信客户端会 ...

  7. python:微信对话开放平台自定义API接口(基于腾讯云函数)

    官网:微信对话开放平台 搭建机器人基本大家都会自己弄自己的API接口,所以一定需要公网IP才能访问,想当然就用腾讯云函数咯,脚本自己写. 这里如要给大家讲些避雷的注意事项: 1.基于微信对话开放平台的 ...

  8. 萤石开放平台-怎么做账号之间的联动操作?(设备托管)

    典型场景: 我是一个总部(公司下有多地分部)技术开发者,现在总部让我把所有地区分布的摄像头对接到总部进行统一管理.这类场景无论在连锁门店.工地.养殖的行业下都是常见的技术实现要求. 难点: 需要保证分 ...

  9. 用友U8开放平台的 api接口

    用友U8开放平台: API,提供丰富的业务分类,接口类,业务需求分析可以借鉴其分类架构:

最新文章

  1. 事务隔离级别IsolationLevel
  2. 计算机共享盒子,电脑之间如何共享文件
  3. JavaScript中this关键字的使用比较
  4. CentOS6.6 32位 Minimal版本纯编译安装Nginx Mysql PHP Memcached
  5. java Structs 介绍
  6. CSDN x BSV|区块链工程师能力初级认证正式启动
  7. 实验室常用质控规则介绍
  8. 小红书前端开发面试经验分享
  9. 编辑PDF时怎样删除文件中的图片
  10. 非线性最小二乘求解方法详解
  11. win10系统进不了服务器失败,快速解决Win10安装失败重启进不了系统的方法
  12. php 微信公共平台开发
  13. chemdraw20.0新功能及使用教程、安装教程
  14. app端-留存分析-周留存率报表开发
  15. 【CUDA开发】CUDA的安装、Nvidia显卡型号及测试
  16. Vulnhub-Moneybox
  17. 联想拯救者R7000P加硬盘
  18. P4169 [Violet]天使玩偶/SJY摆棋子 [CDQ分治]
  19. 幻读和不可重复读的区别
  20. 如何写出漂亮的代码——臃肿的service

热门文章

  1. 学习论文写作“套路”后
  2. 视觉slam学习|基础篇01
  3. InfoQ中文站特供稿件:Rust编程语言的核心部件
  4. VV overall
  5. Win11无法删除文件夹怎么办?Win11无法删除文件夹的解决方法
  6. Python暴力破解wifi密码,你看了你也行
  7. VM虚拟机只有IPv6,没有ipv4
  8. MIT 6.828 学习笔记4 Lab2实验报告
  9. 关于磁链与电感的理解
  10. 【快代理API】查询隧道代理当前IP