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

安全性

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

功能介绍

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

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

目前我采用了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)操作,第二个参数为使用的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));
    }
}


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

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术武器库

一句真诚的谢谢,胜过千言万语

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值