java json接口加密解密

java json接口加密解密

对json接口进行加密解密, 这里实现的方式是 解密使用自定义过滤器

1、启动类加注解@ServletComponentScan

@SpringBootApplication
@ServletComponentScan
public class TestWebApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestWebApplication.class, args);
	}

}

2、创建一个自定义Filter


/**
 * 解密过滤器
 */
@Order(1)
@WebFilter({"/*"})
public class DecodeFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(DecodeFilter.class);

    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
        String contentType = req.getContentType();
        String url = req.getRequestURI();
        //判断是否是json形式请求
        if (StringUtils.isNotBlank(contentType) && contentType.contains("application/json")) {
            //获取request的请求数据
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(req.getInputStream(), "UTF-8"));
            StringBuilder responseStrBuilder = new StringBuilder();
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null)
                responseStrBuilder.append(inputStr);
            //请求json
            JSONObject jsonObject = JSONObject.parseObject(responseStrBuilder.toString());
            //是否加密, 是则进行解密
            if (jsonObject != null && StringUtils.isNotBlank(jsonObject.getString("isEnc"))
                    && jsonObject.getString("isEnc").equals("Y")) {

                //获取request的请求数据
                String bodyInfoEn = jsonObject.getString("content");
                //解密密钥
                String sKey = jsonObject.getString("sKey");

                if (StringUtils.isNotEmpty(bodyInfoEn)) {
                    logger.info("参数解密前: {}", bodyInfoEn);

                    //解密后字符串
                    String bodyInfoDe = AESOperator.getInstance().decrypt(bodyInfoEn, sKey);

                    logger.info("url: {}, 解密后: {}", req.getRequestURI(), bodyInfoDe);

                    if (StringUtils.isNotEmpty(bodyInfoDe)) {

                        //由于request请求没有修改参数的权限,使用篡改后的request代替原先的
                        BodyRequestWrapper requestWrapper = new BodyRequestWrapper(req, bodyInfoDe);

                        chain.doFilter(requestWrapper, res);
                        return;
                    }
                }
                //如果content不存在则返回错误信息
                res.setCharacterEncoding("UTF-8");
                res.setContentType("application/json; charset=utf-8");
                PrintWriter out = res.getWriter();
                try {
                    //加密返回
                    String encrypt = AESOperator.getInstance().encrypt(("缺少必要参数"), AESOperator.skey);
                    out.print(JSONObject.toJSONString(new ApiResult<>(encrypt)));
                    out.flush();
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                //非加密 直接请求
                String param = jsonObject.toJSONString();
                BodyRequestWrapper requestWrapper = new BodyRequestWrapper(req, param);
                chain.doFilter(requestWrapper, res);
            }
        } else {
            //过滤请求
            chain.doFilter(req, res);
        }
    }
}

篡改request


public class BodyRequestWrapper extends HttpServletRequestWrapper {

    private byte[] body;

    public BodyRequestWrapper(HttpServletRequest request, String json) throws IOException {
        super(request);
        body = json.getBytes();
    }

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

    /**
     * 在使用@RequestBody注解的时候,其实框架是调用了getInputStream()方法,所以我们要重写这个方法
     *
     * @return
     * @throws IOException
     */
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);

        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();
            }
        };
    }
}

使用AES 加密解密


/**
 * AES 是一种可逆加密算法,对用户的敏感信息加密处理 对原始数据进行AES加密后,在进行Base64编码转化;
 */

public class AESOperator {

    /*
     * 加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
     */
    public static final String skey = "smkldospdosldaaa";//key,可自行修改
    private String ivParameter = "1016449182158477";//偏移量,可自行修改
    private static AESOperator instance = null;

    private AESOperator() {

    }

    public static AESOperator getInstance() {
        if (instance == null)
            instance = new AESOperator();
        return instance;
    }

    public static String Encrypt(String encData, String secretKey, String vector) throws Exception {

        if (secretKey == null) {
            return null;
        }
        if (secretKey.length() != 16) {
            return null;
        }
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] raw = secretKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(encData.getBytes("utf-8"));
        return new BASE64Encoder().encode(encrypted);// 此处使用BASE64做转码。
    }


    // 加密
    public String encrypt(String sSrc, String sKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] raw = sKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
        return replace(new BASE64Encoder().encode(encrypted));// 此处使用BASE64做转码。
    }

    // 解密
    public String decrypt(String sSrc, String sKey) {
        try {
            byte[] raw = sKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);// 先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original, "utf-8");
            return originalString;
        } catch (Exception ex) {
            return null;
        }
    }

    public String decrypt(String sSrc, String key, String ivs) throws Exception {
        try {
            byte[] raw = key.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(ivs.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);// 先用base64解密
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original, "utf-8");
            return originalString;
        } catch (Exception ex) {
            return null;
        }
    }

    public static String encodeBytes(byte[] bytes) {
        StringBuffer strBuf = new StringBuffer();

        for (int i = 0; i < bytes.length; i++) {
            strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a')));
            strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a')));
        }

        return strBuf.toString();
    }

    /**
     * 去除 换行符、制表符
     * @param str
     * @return
     */
    public String replace(String str) {
        if (!StringUtil.isEmpty(str)) {
            return str.replaceAll("\r|\n", "");
        }
        return str;
    }

    public static void main(String[] args) throws Exception {
        // 需要加密的字串
        String cSrc = "{\"loginName\":\"test\",\"secret\":\"123456\"}";

        // 加密
        String enString = AESOperator.getInstance().encrypt(cSrc, skey);
        System.out.println("加密后的字串是:" + enString);

        // 解密
        String DeString = AESOperator.getInstance().decrypt(enString, skey);
        System.out.println("解密后的字串是:" + DeString);
    }

3、这里加密返回用aop

		<!-- AOP -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

@Aspect // 表示该类是一个通知类
@Configuration //spring注解方式bean注入 交给spring管理
public class ResultAspect {

    private static Logger logger = LoggerFactory.getLogger(ResultAspect.class);

    // 定义切点Pointcut
    @Pointcut("execution(* com.test.controller.api..*(..))")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();

        // result的值就是被拦截方法的返回值
        Object result = pjp.proceed();
        logger.info("请求结束,controller的返回值是 " + JSONObject.toJSONString(result));
        String contentType = request.getContentType();
        String url = request.getRequestURI();
        String sKey = AESOperator.skey;
        logger.info("加密返回:url = {} skey = {}", url, sKey);
        String encrypt = AESOperator.getInstance().encrypt(JSONObject.toJSONString(result), sKey);

        return new ApiResult<>(encrypt);
    }
}


测试请求:

	{ 
	    "isEnc": "Y",
	    "content": "n7XJKiXTxMOBBwaSIRLtbJPtLy6tZ4AsVPimyOctSzglYO4pmQng4lb9wVnjmihb",
	    "sKey": "smkldospdosldaaa"
	}

你可能感兴趣的:(java json接口加密解密)