首先 - AES加密的工具类,将密钥通过枚举类进行保存。
package com.ha.common.utils;
import com.ha.common.enums.EncryptEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* @author pph
* @date 2022/7/8 9:54
* @desciption
*/
@Slf4j
public class AesUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(AesUtils.class);
/**
* key 加密算法
*/
private static final String KEY_ALGORITHM = "AES";
/**
* 固定值
*/
private static final String SECRET_RANDOM = "SHA1PRNG";
/**
* 编码方式
*/
public static final String ENCODING_TYPE = "UTF-8";
/**
* 默认的加密算法
*/
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
/**
* 私钥
*/
private static final String ASSETS_DEV_PWD_FIELD = EncryptEnum.ENCRYPT_ENUM.getCode();
/**
* 加密
*/
public static String encrypt(String content, String password) {
try {
// 创建密码器
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
byte[] byteContent = content.getBytes(ENCODING_TYPE);
// 初始化为加密模式的密码器
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
// 加密
byte[] result = cipher.doFinal(byteContent);
// 通过Base64转码返回
return Base64Utils.encodeToString(result);
} catch (Exception e) {
LOGGER.info("aesencrypt000 error ", e);
}
return null;
}
/**
* AES 解密
*/
public static String decrypt(String content, String password) {
try {
//实例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
SecretKeySpec secretKey = getSecretKey(password);
//执行操作
byte[] result = cipher.doFinal(Base64Utils.decodeFromString(content));
// Base64 base64 = new Base64();
// byte[] result = base64.decodeBase64(password.getBytes());
return new String(result, "utf-8");
} catch (Exception e) {
LOGGER.info("aesdecrypt000 error ", e);
}
return null;
}
/**
* 生成加密秘钥
*/
private static SecretKeySpec getSecretKey(String password) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom secureRandom = SecureRandom.getInstance(SECRET_RANDOM);
secureRandom.setSeed(password.getBytes());
//AES 要求密钥长度为 128
kg.init(128, secureRandom);
//生成一个密钥
SecretKey secretKey = kg.generateKey();
// 转换为AES专用密钥
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
LOGGER.info("aesgetSecretKey000 error ", e);
}
return null;
}
public static void main(String[] args) {
String str="MK9wOrPiGGT1eCc5ovV9ggZPBD7HjsrW6HOOnD0mMd5sTF/IupPGJBelRKgpPPZGxdbap2VGqLu44OU4tv0EmnRUdP8mkLyO7Rodw88qEFav8jyP8TnVxpRrjWOZCo+6";
System.out.println(AesUtils.decrypt(str, EncryptEnum.ENCRYPT_ENUM.getCode()));
System.out.println("---------------------------");
String str1="BwZiUICxJIZ4Ua7VrdZTVEubw/UCNB/sxcS6iqswaT3lU942bfjbZyIdlO3IWkEWhxoG9vqBwZjL+ysL83gtiK+ZHEf/wJl8orRi0Ty3IsWmC7voZch2bOsVzQRQqGSHCq99iiBysmeGZh5PxrIspYy+O6AN/nTvi9t3Mj3JfK9vKcv+fq6ypqt5XyUaXQkcOR4rUELM9YtU78c9zkS994Z0EgwInGZJXKZxsb3qEiu6jAu2FUWYs8OtjM3XjfaZV3bVuvTNMbjJIRSkbvpi8m2hvmLjBYBj163ptqPuNxYX9Kyw2aK4nHO9ictlz0BDWjtVaKi0923HVKUvDFN5JtPXd1FPrg7N7+L56+jKsPfBVX4wjmCrj1RK/oZEjUDNwzXfAnYQA9dMSur8Clkcc0fN0qjBScu7DUBkWainnhC0U0jHCp04/lPMTlXgmhaOnXEakozP3g8M0KvO3CSRwWUGU119ZIEbUPZtaSv6SiNbLDn7jLM4n1cS3XgS663J1zr8CmC7cBeaJL6GnpLaEvqhaafwidTcdueM5KABji/VhX4N9EfZd0G7T2qMkitmDLNCw9BMsIi1tBnbsZU2+rln7baowVZnRyG6SDGHDiFKDlyvWU4MUJPqxI6xm8rnsPYTdIW5KOo//1OQqqMTy/yRz33IJQa8tWBGbGEr2Hs91ItH4DlLlowI0RIAHhYwpqN1EsYhU+lkyeba7uuz8hdkPXenJnW70xuYT2sFqYWVBeFCXV0aqxzpvqVAiGiJdEo5gnKUNVCaKlsXbOEKjfSpLYzMUwcRw8b9V8VdsPlkxBc3talx86eJvdOlGo0HrTuKfxv6nS0rSR9xH50VTPx2IvcPTEYMe9398nkdbQoH5gA7pfOHB39m6W6WLS1SGLhA8A8ucvh+iRvmiSGWW6lTptsQW0AVlGbQaqZMF5sBHZV0Of6HUB9JFZylJTE71oD4J9JZZdphmKozJuLtWtYiNb/H80TBDUoph1n3HTU=";
System.out.println(AesUtils.decrypt(str1, EncryptEnum.ENCRYPT_ENUM.getCode()));
}
}
枚举类 - 设置密钥
package com.ha.common.enums;
/**
* @author pph
* 加解密密钥枚举
*/
public enum EncryptEnum
{
ENCRYPT_ENUM("666666abcdefg");
private final String code;
EncryptEnum(String code)
{
this.code = code;
}
public String getCode()
{
return code;
}
}
本文的方法是通过过滤器进行接口出入参的加解密,这是过滤器的代码部分
2、新建过滤器
这个过滤器没有指定了url进入规则,暂时所有的url都能进入到此过滤器中。在doFilter方法中使用了自定义的ResponseWrapper对response进行封装。Controller接口走完之后获取到接口返回的数据并再次封装到response。
package com.ha.common.filter;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSONObject;
import com.ha.common.enums.EncryptEnum;
import com.ha.common.utils.AesUtils;
/**
* Repeatable 过滤器
*/
public class RepeatableFilter implements Filter
{
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
// chain.doFilter(request, response);
if(((HttpServletRequest) request).getMethod().equals("GET") || ((HttpServletRequest) request).getMethod().equals("POST")||
((HttpServletRequest) request).getMethod().equals("PUT") || ((HttpServletRequest) request).getMethod().equals("DELETE"))
{
String requestURI = ((HttpServletRequest) request).getRequestURI();
//用户登录是否加密解密
// if (requestURI.equals("/busi/user/app/loginByPwd")){
// chain.doFilter(request, response);
// return;
// }
//上传文件不许加解密
if (requestURI.equals("/system/user/profile/avatar")){
chain.doFilter(request, response);
return;
}
AesRequestWrapper aesrequestWrapper = null;
AesResponseWrapper aesResponseWrapper = null;
aesrequestWrapper = new AesRequestWrapper((HttpServletRequest) request);
aesResponseWrapper = new AesResponseWrapper((HttpServletResponse) response);
chain.doFilter(aesrequestWrapper, (ServletResponse) aesResponseWrapper);
// 获取response返回的内容并重新写入response, 若获取到的数据是乱码,可设置response的编码为系统默认编码集
String result = aesResponseWrapper.getResponseData(response.getCharacterEncoding());
//加密
String encryptResponse = AesUtils.encrypt(result, EncryptEnum.ENCRYPT_ENUM.getCode());
Object object = JSONObject.parse(result);
response.getOutputStream().write(encryptResponse.getBytes());
response.getOutputStream().flush();
response.getOutputStream().close();
}
}
@Override
public void destroy()
{
}
/**
* 路径不处理
* @param request
* @param strArr
* @return
*/
public boolean isIgnore(HttpServletRequest request,String[] strArr) {
String path=request.getRequestURI();
for(String ignore:strArr) {
if(path.contains(ignore)) {
return true;
}
}
return false;
}
}
之后就是关于对request请求中body的修改及response的加密。博主这边封装了两个类去解决的。
AesResponseWrapper获取接口的返回值并执行加密
package com.ha.common.filter;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
public class AesResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream buffer = null;
private ServletOutputStream out = null;
private PrintWriter writer = null;
public AesResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
buffer = new ByteArrayOutputStream();
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding()));
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return out;
}
@Override
public PrintWriter getWriter() throws IOException {
return writer;
}
@Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
}
if (writer != null) {
writer.flush();
}
}
@Override
public void reset() {
buffer.reset();
}
/**
* @Description: 获取response中数据的方法
**/
public String getResponseData(String charset) throws IOException {
flushBuffer();//将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据
System.out.println(buffer.toString());
byte[] bytes = buffer.toByteArray();
System.out.println(buffer);
JSONObject parse = (JSONObject) JSONObject.parse(buffer.toString());
System.out.println(parse);
// return new String(bytes, "UTF-8");
return String.valueOf(buffer);
}
//内部类,对ServletOutputStream进行包装,指定输出流的输出端
private class WapperedOutputStream extends ServletOutputStream {
private ByteArrayOutputStream bos = null;
public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException {
bos = stream;
}
//将指定字节写入输出流bos
@Override
public void write(int b) throws IOException {
bos.write(b);
}
@Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
// TODO Auto-generated method stub
}
}
}
AesRequestWrapper获取请求的Body并修改重新带到接口
package com.ha.common.filter;
import com.alibaba.fastjson.JSONObject;
import com.ha.common.enums.EncryptEnum;
import com.ha.common.utils.AesUtils;
import com.ha.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
* @author pph
*/
public class AesRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = LoggerFactory.getLogger(AesRequestWrapper.class);
/**
* 存储请求数据
*/
private String body;
public AesRequestWrapper(HttpServletRequest request) {
super(request);
renewBody(request);
}
/**
* 重写getInputStream方法
*/
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
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() {
return byteArrayInputStream.read();
}
};
}
/**
* 重写getReader方法
*/
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
/**
* 读取body的值
*/
private void renewBody(HttpServletRequest request) {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
if(!StringUtils.isEmpty(stringBuilder)){
String str = stringBuilder.toString();
JSONObject parse = (JSONObject) JSONObject.parse(str);
String data = parse.getString("data");
//data加密代码为空 不解密
if (StringUtils.isEmpty(parse.getString("data"))){
body = str;
return;
}
body = AesUtils.decrypt(data, EncryptEnum.ENCRYPT_ENUM.getCode());
System.out.println(body);
}
}
} catch (Exception ex) {
logger.error("报错请求接口的路径:{}",request.getRequestURI());
logger.error("请求入参aes解密失败:{}",ex);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
logger.error("请求入参base64转换失败:{}",ex);
}
}
}
}
public String getBody() {
return body;
}
}