开发者

Java如何实现http接口参数和返回值加密

开发者 https://www.devze.com 2022-11-28 14:30 出处:网络 作者: 站在墙头上
目录参数和返回值得加密目的具体实现方式大致思路代码实现身份检验参数和返回值得加密目的为了保证接口不被人拦截下来恶意请求,保证程序的稳定性,我们可以使用接口加密的方法来保证参数和返回值的保密性。具体实现...
目录
  • 参数和返回值得加密目的
  • 具体实现方式
    • 大致思路
  • 代码实现
    • 身份检验

参数和返回值得加密目的

为了保证接口不被人拦截下来恶意请求,保证程序的稳定性,我们可以使用接口加密的方法来保证参数和返回值的保密性。

具体实现方式

因为本人是写Java 的,所以这里就直接以Java代码为例。思想都是一样的,只是不同的语言都不同的实现方式。

大致思路

  • 我们的参数和返回值只需要定义两个参数:ak,ct,ak存放堆成加密的秘钥,ct存放加密之后的请求内容。
  • 加密方式用到AES对称加密和RSA非对称加密,将请求参数使用AES加密,HTTP的POST请求和GET请求都可以将实际请求参数的格式定义成同一种格式(比如:jsON格式),便于后台处理。AES加密使用的秘钥用RSA加密。这样我们就不需要操心参数加密的秘钥是什么了,双方都可以随时更换。
  • 使用过滤器获取到请求的加密内容后,通过RSA解密将参数加密的秘钥解析出来,然后再通过解析出来的秘钥通过AES解密去获取实际的请求内容。

注意:不同的请求方式获取参数的方式不同,需要根据不同的请求方式去做不同的解析

代码实现

1. 首先需要一个过滤器,因为我们要拦截请求参数,和加密返回的数据。

因为并不是所有的接口都需要加密,过滤器不能想Spring拦截器那样直接配置拦截和不拦截的类,所以定义了一个ALLOWED_PATHS 集合,用于过滤不需要加解密的请求。然后根据不同的请求方式去解析不同的请求内容,我这里只处理了get请求和post请求这两种常用的请求方式。

package com.pay.filter;

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
* 请求信息加解密
*/
@Log4j2
@Component
@WebFilter(filterName = "EncryptionFilter", urlPatterns = {"/*"})
public class EncryptionFilter implements Filter {

  private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
      Arrays.asList("/pay/notify")));
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if(request instanceof HttpServletRequest) {
      HttpServletRequest hRequest = (HttpServletRequest) request;
      String servletPath = hRequest.getServletPath();
      log.info("request_path:path="+servletPath);
      boolean allow = false;
      for (String allowedPath : ALLOWED_PATHS) {
        if(servletPath.contains(allowedPath)) {
          allow = true;
          break;
        }
      }
      if(allow) {
       chain.doFilter(request, response);
       log.info("no Encryption");
       return;
      }
      MyHttpServletResponseWrapper responseWrapper = new MyHttpServletResponseWrapper((HttpServletResponse) response);
      if(hRequest.getMethod().equalsIgnoreCase("post")) {
        MyHttpServletRequestWrapper requestWrapper = null;
        try {
          requestWrapper = new MyHttpServletRequestWrapper(hRequest);
        } catch (Exception e) {
          request.getRequestDispatcher("404.html").forward(request,response);
        }
        chain.doFilter(requestWrapper, responseWrapper);
      }else if(!hRequest.getMethod().equalsIgnoreCase("options")){
        log.info("收到 potions请求");
      } else { //其余默认get请求
        ParameterRequestWrapper requestWrapper = null;
        try {
          requestWrapper = new ParameterRequestWrapper(hRequest);
        } catch (Exception e) {
          request.getRequestDispatcher("404.html").forward(request,response);
        }
        chain.doFilter(requestWrapper, responseWrapper);
      }
      String resp = responseWrapper.getTextContent(); //获取接口返回内容
      //加密处理返回
      response.getOutputStream().write(HttpEncryptUtil.serverEncrypt(resp).getBytes(StandardCharsets.UTF_8));
    }
  }
}

2. 对于POST请求,定义一个解析request中参数的类 MyHttpServletRequestWrapper继承HttpServletRequestWrapper ,去解析请求参数。

具体实现方式如下:

readBody:实际解析请求参数

package com.pay.filter;

import com.alipay.api.internal.util.file.IOUtils;
import com.pay.util.HttpEncryptUtil;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {

  private String requestBody = null;

  public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
    super(request)javascript;
    requestBody = readBody(request);
  }

  @Override
  public BufferedReader getReader() {
    return new BufferedReader(new InputStreamReader(getInputStream()));
  }

  @Override
  public ServletInputStream getInputStream() {
    final ByteArrayInputStream bais = new ByteArrayI开发者_Js入门nputStream(requestBody.getBytes(StandardCharsets.UTF_8));
    return new ServletInputStream() {
      @Override
      public boolean isFinished() {
        return false;
      }

      @Override
      public boolean isReady() {
        return false;
      }

      @Override
      public void setReadListener(ReadListener readListener) {

      }

      @Override
      public int read() throws IOException {
        return bais.read();
      }
    };
  }

  private static String readBody(ServletRequest request) throws IOException {

    String param = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
    if(StringUtils.isNotBlank(param)) {
      //解密请求参数
      return HttpEncryptUtil.serverDecrypt(param);
    }
    return param;
  }
}

3. 对于get请求,定义一个参数类ParameterRequestWrapper,继承HttpServletRequestWrapper 去解析URL上的参数

具体方式如下:

重载构造方法获取加密之后的参数,去解析出来

ParameterRequestWrapper(HttpServletRequest request)

重写getParameter和setParameter等获取参数和设置参数的方法

package com.pay.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.pay.util.HttpEncryptUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.Map;

public class ParameterRequestWrapper extends HttpServletRequestWrapper {
  private Map<String , String[]> params = new HashMap<String, String[]>();


  @SuppressWarnings("unchecked")
  public ParameterRequestWrapper(HttpServletRequest request) {
    // 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
    super(request);
    //将参数表,赋予给当前的Map以便于持有request中的参数
    //解析
    String ak = request.getParameter("ak");
    String ct = request.getParameter("ct");
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("ak",ak);
    jsonObject.put("ct",ct);
    String s = HttpEncryptUtil.serverDecrypt(jsonObject.toJSONString());
    addAllParameters(JSON.parseobject(s));
  }
  //重载一个构造方法
  public ParameterRequestWrapper(HttpServletRequest request , Map<String , Object> extendParams) {
    this(request);
    addAllParameters(extendParams);//这里将扩展参数写入参数表
  }

  @Override
  public String getParameter(String name) {//重写getParameter,代表参数从当前类中的map获取
    String[]values = params.get(name);
    if(values == null || values.length == 0) {
      return null;
    }
    return values[0];
  }

  public String[] getParameterValues(String name) {//同上
    return params.get(name);
  }

  public void addAllParameters(Map<String , Object>otherParams) {//增加多个参数
    for(Map.Entry<String , Object>entry : otherParams.entrySet()) {
      addParameter(entry.getKey() , entry.getValue());
    }
  }


  public void addParameter(String name , Object value) {//增加参数
    if(value != null) {
      if(value instanceof String[]) {
        params.put(name , (String[])value);
      }else if(value instanceof String) {
        params.put(name , new String[] {(String)value});
      }else {
        params.put(name , new String[] {String.valueOf(value)});
      }
    }
  }
}

注意:为了便于区分我才把获取post请求内容和get请求内容的类写成了两个,其实可以尝试着去将两个解析类合成一个

4. 加解密工具类 HttpEncryptUtil ,和两个网上百度的AESUtil,RSAUtil

package com.pay.util;

import com.alibaba.fastjson.JSONObject;
import com.pay.common.Constant;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.interfaces.RSAPublicKey;

public class HttpEncryptUtil {

  //解密请求内容
  public static String serverDecrypt(String content) {
    JSONObject result = JSONObject.parseObject(content);
    String encryptAesKeyStr = result.getString("ak");
    String encryptContent = result.getString("ct");
    //使用私钥解密 获取解密内容的AES密钥
//    encryptAesKeyStr = decodeBase64String(encryptAesKeyStr); //base64解码

    PrivateKey privateKey = RSAUtil.getPrivateKey(HTTP_PRIVATE_KEY);
    String aesKey = RSAUtil.decryptByPrivate(decodeBase64String(encryptAesKeyStr), privateKey);
    //使用解密出来的key解密content:使用AES
    return AESUtil.decryptAES(decodeBase64String(encryptContent), aesKey);
  }

  public static String serverDecryptByPublic(String content) {
    JSONObject result = JSONObject.parseObject(content);
    String encryptAesKeyStr = result.getString("ak");
    String encryptContent = result.getString("ct");
    //使用私钥解密 获取解密内容的AES密钥
//    encryptAesKeyStr = decodeBase64String(encryptAesKeyStr); //base64解码
    RSAPublicKey publicKey = RSAUtil.getPublicKey(HTTP_PUBLIC_KEY);
    String aesKey = RSAUtil.decryptByPublic(decodeBase64String(encryptAesKeyStr), publicKey);
    //使用解密出来的key解密content:使用AES
    return AESUtil.decryptAES(decodeBase64String(encryptContent), aesKey);
  }

  //加密返回内容
  public static String serverEncrypt(String content) {
    String aesKey = HTTP_CONTENT_KEY;
    //使用私钥加密AES的key
    PrivateKey privateKey = RSAUtil.getPrivateKey(HTTP_PRIVATE_KEY);
    String ak = RSAUtil.encryptByPrivate(aesKey.getBytes(StandardCharsets.UTF_8), privateKey);
    String ct = AESUtil.encryptAES(content, aesKey);
    JSONObject result = new JSONObject();
    result.put("ak",encodeBase64String(ak));
    result.put("ct",encodeBase64String(ct));
    return result.toJSONString();
  }

  public static String serverEncryptByPublic(String content) {
    String aesKey = HTTP_CONTENT_KEY;
    //使用公钥钥加密AES的key
    RSAPublicKey publicKey = RSAUtil.getPublicKey(HTTP_PUBLIC_KEY);
    String ak = RSAUtil.encryptByPublic(aesKey.getBytes(StandardCharsets.UTF_8), publicKey);
    String ct = AESUtil.encryptAES(content, aesKey);
    JSONObject result = new JSONObject();
    result.put("ak",encodeBase64String(ak));
    result.put("ct",encodeBase64String(ct));
    return result.toJSONString();
  }


  public static String encodeBase64String(String content) {
    if(StringUtils.isBlank(content)) {
      return null;
    }
    return Base64.encodeBase64String(content.getBytes(StandardCharsets.UTF_8));
  }

  public static String decodeBase64String(String content) {
    if(StringUtils.isBlank(content)) {
      return null;
    }
    return new String(Base64.decodeBase64(content), StandardCharsets.UTF_8);
  }
}
package com.pay.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AESUtil {

  public static final Charset CHARSET = StandardCharsets.UTF_8;
  public static final String ALGORITHMS_MD5 = "MD5";
  public static final String SHA = "SHA1PRNG";

  public static final String ALGORITHM = "AES";

  /**
  * 加密
  *
  * @param content 需要加密的内容
  * @param password 加密密码
  * @return
  */
  public static byte[] encrypt(String content, String password) {
    try {
      KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM);
      SecureRandom random = SecureRandom.getInstance(SHA);
      random.setSeed(password.getBytes());
      kgen.init(128, random);
      SecretKey secretKey = kgen.generateKey();
      byte[] enCodeFormat = secretKey.getEncoded();
      SecretKeySpec key = new SecretKeySpec(enCodeFormat, ALGORITHM);
      Cipher cipher = Cipher.getInstance(ALGORITHM);// 创建密码器
      byte[] byteContent = content.getBytes(CHARSET);
      cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
      return cipher.doFinal(byteContent); // 加密
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  /**
  * 解密
  *
  * @param content 待解密内容
  * @param password 解密密钥
  * @return
  */
  public static byte[] decrypt(byte[] content, String password) {
    try {
      KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM);
      SecureRandom random = SecureRandom.getInstance(SHA);
      random.setSeed(password.getBytes());
      kgen.init(128, random);
      SecretKey secretKey = kgen.generateKey();
      byte[] enCodeFormat = secretKey.getEncoded();
      SecretKeySpec key = new SecretKeySpec(enCodeFormat, ALGORITHM);
      Cipher cipher = Cipher.getInstance(ALGORITHM);// 创建密码器
      cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
      return cipher.doFinal(content); // 加密
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  /**
  * 将二进制转换成16进制
  *
  * @param buf
  * @return
  */
  public static String parseByte2HexStr(byte buf[]) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < buf.length; i++) {
      String hex = Integer.toHexString(buf[i] & 0xFF);
      if (hex.length() == 1) {
        hex = '0' + hex;
      }
      sb.append(hex.toUpperCase());
    }
    return sb.toString();
  }

  /**
  * 将16进制转换为二进制
  *
  * @param hexStr
  * @return
  */
  public static byte[] parseHexStr2Byte(String hexStr) {
    if (hexStr.length() < 1)
      return null;
    byte[] result = new byte[hexStr.length() / 2];
    for (int i = 0; i < hexStr.length() / 2; i++) {
      int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
      int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
      result[i] = (byte) (high * 16 + low);
    }
    return result;
  }

  private static byte[] DOSign(String algorithms, String inputStr) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance(algorithms);
    messageDigest.update(inputStr.getBytes(CHARSET));
    return messageDigest.digest();
  }

  private static String signToHexStr(String algorithms, String inputStr) {
    try {
      return parseByte2HexStr(doSign(algorithms, inputStr));
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
      return null;
    }
  }

  public static String sign(String key, String sourceStr) {
    String md5Str1 = signToHexStr(ALGORITHMS_MD5, sourceStr);
    String sourceStr2 = md5Str1 + key;
    return signToHexStr(ALGORITHMS_MD5, sourceStr2);
  }

  public static String toDecryptParam(String sourceStr, String password){
    try {
      byte[] sourceByte = parseHexStr2Byte(sourceStr);
      byte[] bytes = decrypt(sourceByte, password);
      return new String(bytes,CHARSET);
    }catch (Exception e){
      e.printStackTrace();
    }
    return "";
  }

  public static String toEncryptResult(Object sourceStr, String password){
    String parameterJson = JSONObject.toJSONString(sourceStr);
    byte[] encode = encrypt(parameterJson, password);
    return parseByte2HexStr(encode);
  }

  public static String encryptAES(String content, String password) {
    try {
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      byte[] byteContent = content.getBytes("utf-8");
      cipher.init(1, getSecretKey(password));
      byte[] result = cipher.doFinal(byteContent);
      return Base64.encodeBase64String(result);
    } catch (Exception var5) {
      return null;
    }
  }

  public static String decryptAES(String content, String password) {
    try {
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      cipher.init(2, getSecretKey(password));
      byte[] result = cipher.doFinal(Base64.decodeBase64(content));
      return new String(result, "utf-8");
    } catch (Exception var4) {
      return null;
    }
  }
  private static SecretKeySpec getSecretKey(String password) {
    KeyGenerator kg = null;

    try {
      kg = KeyGenerator.getInstance("AES");
      SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
      random.setSeed(password.getBytes());
      kg.init(128, random);
      SecretKey secretKey = kg.generateKey();
      return new SecretKeySpec(secretKey.getEncoded(), "AES");
    } catch (NoSuchAlgorithmException var4) {
      return null;
    }
  }
package com.pay.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalblockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

/**
* RSA算法加密/解密工具类
*/
@Slf4j
public class RSAUtil {
  /** 算法名称 */
  private static final String ALGORITHM = "RSA";
  /** 默认密钥大小 */
  private static final int KEY_SIZE = 1024;
  /** 用来指定保存密钥对的文件名和存储的名称 */
  private static final String PUBLIC_KEY_NAME = "publicKey";
  private static final String PRIVATE_KEY_NAME = "privateKey";
  private static final String PUBLIC_FILENAME = "publicKey.properties";
  private static final String PRIVATE_FILENAME = "privateKey.properties";
  /** 密钥对生成器 */
  private static
  KeyPairGenerator keyPairGenerator = null;

  private static KeyFactory keyFactory = null;
  /** 缓存的密钥对 */
  private static KeyPair keyPair = null;
  /** Base64 编码/解码器 JDK1.8 */
  private static Base64.Decoder decoder = Base64.getDecoder();
  private static Base64.Encoder encoder = Base64.getEncoder();
  /** 初始化密钥工厂 */
  static{
    try {
      keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
      keyFactory = KeyFactory.getInstance(ALGORITHM);
    } catch (NoSuchAlgorithmException e) {
      log.error("RSAUtil[ERROR]:e={}",e);
    }
  }
  /** 私有构造器 */
  private RSAUtil(){}

  /**
  * 生成密钥对
  * 将密钥分别用Base64编码保存到#publicKey.properties#和#privateKey.properties#文件中
  * 保存的默认名称分别为publicKey和privateKey
  */
  public static synchronized Map<String, Object> generateKeyPair(){
    try {
      keyPairGenerator.initialize(KEY_SIZE,new SecureRandom(UUID.randomUUID().toString().replaceAll("-","").getBytes()));
      keyPair = keyPairGenerator.generateKeyPair();
    } catch (InvalidParameterException e){
      log.error("KeyPairGenerator does not support a key length of " + KEY_SIZE + ".",e);
    } catch (NullPointerException e){
      log.error("RSAUtil#key_pair_gen is null,can not generate KeyPairGenerator instance.",e);
    }
    RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
    RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
    String publicKeyString = encoder.encodeToString(rsaPublicKey.getEncoded());
    String privateKeyString = encoder.encodeToString(rsaPrivateKey.getEncoded());
    storeKey(publicKeyString,PUBLIC_KEY_NAME,PUBLIC_FILENAME);
    storeKey(privateKeyString,PRIVATE_KEY_NAME,PRIVATE_FILENAME);
    Map<String, Object> keyPair = new HashMap<>();
    keyPair.put("public", publicKeyString);
    keyPair.put("private", privateKeyString);
    return keyPair;
  }

  /**
  * 将指定的密钥字符串保存到文件中,如果找不到文件,就创建
  * @param keyString 密钥的Base64编码字符串(值)
  * @param keyName 保存在文件中的名称(键)
  * @param fileName 目标文件名
  */
  private static void storeKey(String keyString,String keyName,String fileName){
    Properties properties = new Properties();
    //存放密钥的绝对地址
    String path = null;
    try{
      path = RSAUtil.class.getClassLoader().getResource(fileName).toString();
      path = path.substring(path.indexOf(":") + 1);
    }catch (NullPointerException e){
      //如果不存#fileName#就创建
      log.warn("storeKey()# " + fileName + " is not exist.Begin to create this file.");
      String classPath = RSAUtil.class.getClassLoader().getResource("").toString();
      String prefix = classPath.substring(classPath.indexOf(":") + 1);
      String suffix = fileName;
      File file = new File(prefix + suffix);
      try {
        file.createNewFile();
        path = file.getAbsolutePath();
      } catch (IOException e1) {
        log.error(fileName +" create fail.",e1);
      }
    }
    try(OutputStream out = new FileOutputStream(path)){
      properties.setProperty(keyName,keyString);
      properties.store(out,"There is " + keyName);
    } catch (FileNotFoundException e) {
      log.error("ModulusAndExponent.properties is not found.",e);
    } catch (IOException e) {
      log.error("OutputStream output failed.",e);
    }
  }

  /**
  * 获取密钥字符串
  * @param keyName 需要获取的密钥名
  * @param fileName 密钥所在文件
  * @return Base64编码的javascript密钥字符串
  */
  private static String getKeyString(String keyName,String fileName){
    if (RSAUtil.class.getClassLoader().getResource(fileName) == null){
      log.warn("getKeyString()# " + fileName + " is not exist.Will run #generateKeyPair()# firstly.");
      generateKeyPair();
    }
    try(InputStream in = RSAUtil.class.getClassLoader().getResource(fileName).openStream()){
      Properties properties = new Properties();
      properties.load(in);
      return properties.getProperty(keyName);
    } catch (IOException e) {
      log.error("getKeyString()#" + e.getMessage(),e);
    }
    retandroidurn null;
  }

  /**
  * 从文件获取RSA公钥
  * @return RSA公钥
  * @throws InvalidKeySpecException
  */
  public static RSAPublicKey getPublicKey(){
    try {
      byte[] keyBytes = decoder.decode(getKeyString(PUBLIC_KEY_NAME,PUBLIC_FILENAME));
      X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
      return (RSAPublicKey)keyFactory.generatePublic(x509EncodedKeySpec);
    }catch (InvalidKeySpecException e) {
      log.error("getPublicKey()#" + e.getMessage(),e);
    }
    return null;
  }

  public static RSAPublicKey getPublicKey(String publicKeyString) {
    if(StringUtils.isBlank(publicKeyString)) {
      return null;
    }
    try {
      byte[] keyBytes = decoder.decode(publicKeyString);
      X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
      return (RSAPublicKey)keyFactory.generatePublic(x509EncodedKeySpec);
    }catch (InvalidKeySpecException e) {
      log.error("getPublicKey()#" + e.getMessage(),e);
    }
    return null;
  }

  /**
  * 从文件获取RSA私钥
  * @return RSA私钥
  * @throws InvalidKeySpecException
  */
  public static RSAPrivateKey getPrivateKey(){
    try {
      byte[] keyBytes = decoder.decode(getKeyString(PRIVATE_KEY_NAME,PRIVATE_FILENAME));
      PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
      return (RSAPrivateKey)keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    } catch (InvalidKeySpecException e) {
      log.error("getPrivateKey()#" + e.getMessage(),e);
    }
    return null;
  }

  public static RSAPrivateKjsey getPrivateKey(String privateKeyString) {
    if(StringUtils.isBlank(privateKeyString)) {
      return null;
    }
    try {
      byte[] keyBytes = decoder.decode(privateKeyString);
      PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
      return (RSAPrivateKey)keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    } catch (InvalidKeySpecException e) {
      log.error("getPrivateKey()#" + e.getMessage(),e);
    }
    return null;
  }

  /**
  * RSA公钥加密
  * @param content 等待加密的数据
  * @param publicKey RSA 公钥 if null then getPublicKey()
  * @return 加密后的密文(16进制的字符串)
  */
  public static String encryptByPublic(byte[] content,PublicKey publicKey){
    if (publicKey == null){
      publicKey = getPublicKey();
    }
    try {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.ENCRYPT_MODE,publicKey);
      //该密钥能够加密的最大字节长度
      int splitLength = ((RSAPublicKey)publicKey).getModulus().bitLength() / 8 -11;
      byte[][] arrays = splitBytes(content,splitLength);
      StringBuffer stringBuffer = new StringBuffer();
      for (byte[] array : arrays){
        stringBuffer.append(bytesToHexString(cipher.doFinal(array)));
      }
      return stringBuffer.toString();
    } catch (NoSuchAlgorithmException e) {
      log.error("encrypt()#NoSuchAlgorithmException",e);
    } catch (NoSuchPaddingException e) {
      log.error("encrypt()#NoSuchPaddingException",e);
    } catch (InvalidKeyException e) {
      log.error("encrypt()#InvalidKeyException",e);
    } catch (BadPaddingException e) {
      log.error("encrypt()#BadPaddingException",e);
    } catch (IllegalBlockSizeException e) {
      log.error("encrypt()#IllegalBlockSizeException",e);
    }
    return null;
  }

  /**
  * RSA私钥加密
  * @param content 等待加密的数据
  * @param privateKey RSA 私钥 if null then getPrivateKey()
  * @return 加密后的密文(16进制的字符串)
  */
  public static String encryptByPrivate(byte[] content,PrivateKey privateKey){
    if (privateKey == null){
      privateKey = getPrivateKey();
    }
    try {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.ENCRYPT_MODE,privateKey);
      //该密钥能够加密的最大字节长度
      int splitLength = ((RSAPrivateKey)privateKey).getModulus().bitLength() / 8 -11;
      byte[][] arrays = splitBytes(content,splitLength);
      StringBuffer stringBuffer = new StringBuffer();
      for(byte[] array : arrays){
        stringBuffer.append(bytesToHexString(cipher.doFinal(array)));
      }
      return stringBuffer.toString();
    } catch (NoSuchAlgorithmException e) {
      log.error("encrypt()#NoSuchAlgorithmException",e);
    } catch (NoSuchPaddingException e) {
      log.error("encrypt()#NoSuchPaddingException",e);
    } catch (InvalidKeyException e) {
      log.error("encrypt()#InvalidKeyException",e);
    } catch (BadPaddingException e) {
      log.error("encrypt()#BadPaddingException",e);
    } catch (IllegalBlockSizeException e) {
      log.error("encrypt()#IllegalBlockSizeException",e);
    }
    return null;
  }

  /**
  * RSA私钥解密
  * @param content 等待解密的数据
  * @param privateKey RSA 私钥 if null then getPrivateKey()
  * @return 解密后的明文
  */
  public static String decryptByPrivate(String content,PrivateKey privateKey){
    if (privateKey == null){
      privateKey = getPrivateKey();
    }
    try {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.DECRYPT_MODE,privateKey);
      //该密钥能够加密的最大字节长度
      int splitLength = ((RSAPrivateKey)privateKey编程客栈).getModulus().bitLength() / 8;
      byte[] contentBytes = hexStringToBytes(content);
      byte[][] arrays = splitBytes(contentBytes,splitLength);
      StringBuffer stringBuffer = new StringBuffer();
      String sTemp = null;
      for (byte[] array : arrays){
        stringBuffer.append(new String(cipher.doFinal(array)));
      }
      return stringBuffer.toString();
    } catch (NoSuchAlgorithmException e) {
      log.error("encrypt()#NoSuchAlgorithmException",e);
    } catch (NoSuchPaddingException e) {
      log.error("encrypt()#NoSuchPaddingException",e);
    } catch (InvalidKeyException e) {
      log.error("encrypt()#InvalidKeyException",e);
    } catch (BadPaddingException e) {
      log.error("encrypt()#BadPaddingException",e);
    } catch (IllegalBlockSizeException e) {
      log.error("encrypt()#IllegalBlockSizeException",e);
    }
    return null;
  }

  /**
  * RSA公钥解密
  * @param content 等待解密的数据
  * @param publicKey RSA 公钥 if null then getPublicKey()
  * @return 解密后的明文
  */
  public static String decryptByPublic(String content,PublicKey publicKey){
    if (publicKey == null){
      publicKey = getPublicKey();
    }
    try {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.DECRYPT_MODE,publicKey);
      //该密钥能够加密的最大字节长度
      int splitLength = ((RSAPublicKey)publicKey).getModulus().bitLength() / 8;
      byte[] contentBytes = hexStringToBytes(content);
      byte[][] arrays = splitBytes(contentBytes,splitLength);
      StringBuffer stringBuffer = new StringBuffer();
      String sTemp = null;
      for (byte[] array : arrays){
        stringBuffer.append(new String(cipher.doFinal(array)));
      }
      return stringBuffer.toString();
    } catch (NoSuchAlgorithmException e) {
      log.error("encrypt()#NoSuchAlgorithmException",e);
    } catch (NoSuchPaddingException e) {
      log.error("encrypt()#NoSuchPaddingException",e);
    } catch (InvalidKeyException e) {
      log.error("encrypt()#InvalidKeyException",e);
    } catch (BadPaddingException e) {
      log.error("encrypt()#BadPaddingException",e);
    } catch (IllegalBlockSizeException e) {
      log.error("encrypt()#IllegalBlockSizeException",e);
    }
    return null;
  }

  /**
  * 根据限定的每组字节长度,将字节数组分组
  * @param bytes 等待分组的字节组
  * @param splitLength 每组长度
  * @return 分组后的字节组
  */
  public static byte[][] splitBytes(byte[] bytes,int splitLength){
    //bytes与splitLength的余数
    int remainder = bytes.length % splitLength;
    //数据拆分后的组数,余数不为0时加1
    int quotient = remainder != 0 ? bytes.length / splitLength + 1:bytes.length / splitLength;
    byte[][] arrays = new byte[quotient][];
    byte[] array = null;
    for (int i =0;i<quotient;i++){
      //如果是最后一组(quotient-1),同时余数不等于0,就将最后一组设置为remainder的长度
      if (i == quotient -1 && remainder != 0){
        array = new byte[remainder];
        System.arraycopy(bytes,i * splitLength,array,0,remainder);
      } else {
        array = new byte[splitLength];
        System.arraycopy(bytes,i*splitLength,array,0,splitLength);
      }
      arrays[i] = array;
    }
    return arrays;
  }

  /**
  * 将字节数组转换成16进制字符串
  * @param bytes 即将转换的数据
  * @return 16进制字符串
  */
  public static String bytesToHexString(byte[] bytes){
    StringBuffer sb = new StringBuffer(bytes.length);
    String temp = null;
    for (int i = 0;i< bytes.length;i++){
      temp = Integer.toHexString(0xFF & bytes[i]);
      if(temp.length() <2){
        sb.append(0);
      }
      sb.append(temp);
    }
    return sb.toString();
  }

  /**
  * 将16进制字符串转换成字节数组
  * @param hex 16进制字符串
  * @return byte[]
  */
  public static byte[] hexStringToBytes(String hex){
    int len = (hex.length() / 2);
    hex = hex.toUpperCase();
    byte[] result = new byte[len];
    char[] chars = hex.toCharArray();
    for (int i= 0;i<len;i++){
      int pos = i * 2;
      result[i] = (byte)(toByte(chars[pos]) << 4 | toByte(chars[pos + 1]));
    }
    return result;
  }

  /**
  * 将char转换为byte
  * @param c char
  * @return byte
  */
  private static byte toByte(char c){
    return (byte)"0123456789ABCDEF".indexOf(c);
  }

身份检验

除了参数加密之外,我们还可以做一个简单的身份校验。这里就需要使用到Spring的拦截器了。

可以在header中放一个身份token,拦截器里面校验

具体实现:

一个拦截器 TokenInterceptor.java 和配置类 WebConfig.java

package com.pay.filter;

import com.alibaba.fastjson.JSONObject;
import com.pay.common.ErrorCode;
import com.pay.common.GlobalEnums;
import com.pay.entity.SourceConfig;
import com.pay.service.SourceConfigService;
import com.pay.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

  @Autowired
  private SourceConfigService sourceConfigService;

  @Override
  public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
    String token = httpServletRequest.getHeader("token");
    httpServletResponse.setContentType("text/html;charset=utf-8");
    httpServletResponse.setCharacterEncoding("utf-8");
    ServletOutputStream outputStream = httpServletResponse.getOutputStream();
    JSONObject jsonObject =new JSONObject();
    if(StringUtils.isBlank(token)) {
      jsonObject.put("code", ErrorCode.Ax000014.getCode());
      jsonObject.put("message", ErrorCode.Ax000014.getMessage());
      outputStream.write(jsonObject.toJSONString().getBytes());
      return false;
    }
    SourceConfig sourceConfig = sourceConfigService.selectBySource(token);
    if(sourceConfig == null) {
      jsonObject.put("code", ErrorCode.Ax000014.getCode());
      jsonObject.put("message", ErrorCode.Ax000014.getMessage());
      outputStream.write(jsonObject.toJSONString().getBytes());
      return false;
    }
    if(sourceConfig.getStatus().equals(GlobalEnums.EnableEnum.FALSE.getEnable())) {
      jsonObject.put("code", ErrorCode.Ax000014.getCode());
      jsonObject.put("message", ErrorCode.Ax000014.getMessage());
      outputStream.write(jsonObject.toJSONString().getBytes());
      return false;
    }
    return true;
  }

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object arg2, Exception arg3)
      throws Exception {
    RequestTokenHolder.remove();
  }

}
package com.pay.config;
import com.pay.filter.TokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class WebConfig implements WebMvcConfigurer {

  @Override
  public void addViewControllers(ViewControllerRegistry registry) {

  }

  @Resource
  private TokenInterceptor tokenInterceptor;

  /**
  * 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
  *
  * @param registry ""
  */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(tokenInterceptor)
        .addPathPatterns("/**")
        .excludePathPatterns(
            "/pay/notify/**"//登录接口
        )
        // 过滤swagger
        .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
  }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号