目录
安全性
既然你能看到我这篇文章,就代表你目前或者是你想做或者已经做过接口加解密的功能,做加密的目的一定是为了安全,这是毋庸置疑的。
功能介绍
因为我们要开放我们自己的接口给接入方,所以一些加密和限流是免不了要做的,可以理解为我们要做一个开放平台。
既然要做开放平台,肯定会同时把同一个接口开放给多个接入方,每个接入方的身份标识,私钥、签名都是不一样的。
目前我采用了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)操作,第二个参数为使用的KEY
cipher.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();
}
//如果有错就返加nulll
return 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)操作,第二个参数为使用的KEY
cipher.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();
}
//如果有错就返加nulll
return 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的真实ip
if (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 {
@Autowired
StringRedisTemplate 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;
@Override
public Integer code() {
return code;
}
@Override
public 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();
//得到response
HttpServletResponse response = requestContext.getResponse();
//拒绝访问
requestContext.setSendZuulResponse(false);
//设置响应代码
requestContext.setResponseStatusCode(200);
//转成json
String jsonString = JsonUtil.objectToJson(serverResponse);
requestContext.setResponseBody(jsonString);
//转成json,设置contentType
response.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
*/
@JsonIgnore
public 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;
}
@Override
public 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;
}
@Override
public void write(int datum) throws IOException {
Object var2 = this.lock;
synchronized (this.lock) {
this.out.write(datum);
}
}
@Override
public void write(byte[] data) throws IOException {
Object var2 = this.lock;
synchronized (this.lock) {
this.out.write(data);
}
}
@Override
public void write(byte[] data, int offset, int length) throws IOException {
Object var4 = this.lock;
synchronized (this.lock) {
this.out.write(data, offset, length);
}
}
@Override
public void flush() throws IOException {
Object var1 = this.lock;
synchronized (this.lock) {
this.out.flush();
}
}
@Override
public 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;
@Autowired
private PlatformService platformService;
@Override
public String filterType() {
/*
pre:请求在被路由之前执行
routing:在路由请求时调用
post:在routing和error过滤器之后调用
error:处理请求时发生错误调用
*/
return "pre";
}
@Override
public int filterOrder() {
/*
过虑器序号,越小越被优先执行
*/
return 1;
}
@SneakyThrows
@Override
public 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;
}
@Override
public 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);
}
//增加json
jsonObject.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()) {
@Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(dataContent.getBytes());
}
@Override
public int getContentLength() {
return dataContent.getBytes().length;
}
@Override
public 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 {
@Autowired
private RedisTemplate redisTemplate;
@Value("${openapi.uri.prefix}")
private String openApiPrefix;
@Override
public String filterType() {
/*
pre:请求在被路由之前执行
routing:在路由请求时调用
post:在routing和error过滤器之后调用
error:处理请求时发生错误调用
*/
return "post";
}
@Override
public int filterOrder() {
/*
过虑器序号,越小越被优先执行
*/
return 0;
}
@Override
public boolean shouldFilter() {
//返回true表示要执行此过虑器
RequestContext requestContext = RequestContext.getCurrentContext();
return (boolean) requestContext.get("isOpenApi");
}
@Override
public 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);
//转成json
String 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)操作,第二个参数为使用的KEY
cipher.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();
}
//如果有错就返加nulll
return 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)操作,第二个参数为使用的KEY
cipher.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();
}
//异常返null
return 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-type
httpRequest.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));
}
}
到这双方请求数据和响应数据的加密和解密就完成了,能看出还是有很多东西的,但是毕竟包含了所有东西,你这基本拿过去就能用了,对吧,在做加密和解密的同时也做了接口的限流,后面把接口的限流发布上来供大家参考。