springBoot修改request的body实现CryptoJS前端加密后台Java解密

背景:客户端将加密的数据通过post请求发送到服务端,服务端修改request里的body,将解密后的body给到controller,服务器端请求处理后,统一在响应拦截处将加密后的数据返回给客户端

看效果

 

 1、加解密方法

package com.hi.hailiaowenan.base.utils;

import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

// CryptoJS前端加密后台Java解密
public class DesCipherUtil {
    private static String decryptKey = "aaaabbbbccccdddd";
    private static String encryptKey = "aaaabbbbccccdddd";
    /**
     * AES解密
     * @param encryptStr 密文
     * @param decryptKey 秘钥,必须为16个字符组成
     * @return 明文
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr) throws Exception {
        if (StringUtils.isEmpty(encryptStr) || StringUtils.isEmpty(decryptKey)) {
            return null;
        }
        byte[] encryptByte = Base64.getDecoder().decode(encryptStr);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
        byte[] decryptBytes = cipher.doFinal(encryptByte);
        return new String(decryptBytes);
    }

    /**
     * AES加密
     * @param content 明文
     * @param encryptKey 秘钥,必须为16个字符组成
     * @return 密文
     * @throws Exception
     */
    public static String aesEncrypt(String content) throws Exception {
        if (StringUtils.isEmpty(content) || StringUtils.isEmpty(encryptKey)) {
            return null;
        }

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));

        byte[] encryptStr = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptStr);
     }

     // 测试加密与解密
    //  public static void main(String[] args) {
    //     try {
    //         String secretKey = "aaaabbbbccccdddd";
    //         String content = "{ a: 1, b: 2}";
    //         String s1 = aesEncrypt(content, secretKey);
    //         System.out.println(s1);
    //         String s = aesDecrypt(s1, secretKey);
    //         System.out.println(s);
    //     } catch (Exception e) {
    //         e.printStackTrace();
    //     }
    // }
}

2、通过自定义过滤器,实现controller层的接口解密,并将流继续保存下去

package com.hi.hailiaowenan.base.utils;

import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

// CryptoJS前端加密后台Java解密
public class DesCipherUtil {

    private static final String accessKeySecret = "aaaabbbbccccdddd";

    /**
     * AES解密
     * 
     * @param encryptStr 密文
     * @param decryptKey 秘钥,必须为16个字符组成
     * @return 明文
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr) throws Exception {
        if (StringUtils.isEmpty(encryptStr)) {
            return null;
        }
        byte[] encryptByte = Base64.getDecoder().decode(encryptStr);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(accessKeySecret.getBytes(), "AES"));
        byte[] decryptBytes = cipher.doFinal(encryptByte);
        return new String(decryptBytes);
    }

    /**
     * AES加密
     * 
     * @param content    明文
     * @param encryptKey 秘钥,必须为16个字符组成
     * @return 密文
     * @throws Exception
     */
    public static String aesEncrypt(String content) throws Exception {
        if (StringUtils.isEmpty(content)) {
            return null;
        }

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(accessKeySecret.getBytes(), "AES"));

        byte[] encryptStr = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptStr);
    }

    // 测试加密与解密
    // public static void main(String[] args) {
    // try {
    // String secretKey = "aaaabbbbccccdddd";
    // String content = "{ a: 1, b: 2}";
    // String s1 = aesEncrypt(content, secretKey);
    // System.out.println(s1);
    // String s = aesDecrypt(s1, secretKey);
    // System.out.println(s);
    // } catch (Exception e) {
    // e.printStackTrace();
    // }
    // }
}

3、 重写HttpServletRequestWrapper方法,由于HttpServletRequest中的body数据只能get不能set,即不能重新赋值,并且只能读取一次,但是我们的场景却是需要对body重新赋值,这个时候需要我们想办法重写

package com.hi.hailiaowenan.wrapper;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

// 重写HttpServletRequestWrapper方法
public class RequestWrapper extends HttpServletRequestWrapper {
    private String body;

    public RequestWrapper(HttpServletRequest request, String context) {
        super(request);
        body = context;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = 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 byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }

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

    public String getBody() {
        return this.body;
    }

    public void setBodyJsonStr(String bodyJsonStr) {
        this.body = bodyJsonStr;
    }
}

4、 重写HttpServletResponseWrapper 方法

package com.hi.hailiaowenan.wrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

// 重写HttpServletResponseWrapper方法
public class ResponseWrapper extends HttpServletResponseWrapper {

    private ByteArrayOutputStream buffer;
    private ServletOutputStream out;

    public ResponseWrapper(HttpServletResponse httpServletResponse) {
        super(httpServletResponse);
        buffer = new ByteArrayOutputStream();
        out = new WrapperOutputStream(buffer);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return out;
    }

    @Override
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
    }

    public byte[] getContent() throws IOException {
        flushBuffer();
        return buffer.toByteArray();
    }

    private static class WrapperOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos;

        WrapperOutputStream(ByteArrayOutputStream bos) {
            this.bos = 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 arg0) {

            // TODO Auto-generated method stub

        }
    }
}

4、在启动类中注入

@SpringBootApplication
@ServletComponentScan  //注册过滤器注解 对应filter/ChannelFiliter

完整代码 

package com.hi.hailiaowenan;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.hi.hailiaowenan.base.config.AliConfig;
import com.hi.hailiaowenan.base.config.QqConfig;
import com.hi.hailiaowenan.base.config.WxConfig;
import com.hi.hailiaowenan.base.config.ToutiaoConfig;

@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@EnableConfigurationProperties({WxConfig.class, AliConfig.class, ToutiaoConfig.class, QqConfig.class})
@ComponentScan(basePackages = "com.hi.hailiaowenan.**")
@MapperScan("com.hi.hailiaowenan.**.**.mapper")
@SpringBootApplication
@ServletComponentScan  //注册过滤器注解 对应filter/ChannelFiliter
public class HailiaowenanApplication {
    public static void main(String[] args) {
        SpringApplication.run(HailiaowenanApplication.class, args);
    }
    
    //	redis 乱码序列化、
    @Bean(name = "redisTemplate")
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

至此,完成了客户端加密,服务器端解密参数,并将加密后的数据返回给客户端

参考文章:

SpringBoot通过拦截器获取请求参数和返回结果进行操作 | 码农家园

CryptoJS前端加密后台Java解密 - 简书

springboot过滤器中将form表单和body(json)形式的进参拦截修改里面参数内容(重写HttpServletRequestWrapper里边的方法)_酸菜鱼(szy)的博客-CSDN博客_formbody json

重写Request,修改Request中的Body内容 - 简书

SpringBoot实现数据加密传输_酷酷小饼干的博客-CSDN博客_springboot 加密传输

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端Vue传递加密密文到后端Java,后解密的示例代码如下: 前端Vue加密代码: ```javascript // 导入jsencrypt库 import JSEncrypt from 'jsencrypt' // 创建RSA加密实例 const encrypt = new JSEncrypt() // 设置RSA公钥 const publicKey = 'YOUR_RSA_PUBLIC_KEY' encrypt.setPublicKey(publicKey) // 要加密的数据 const data = 'YOUR_DATA_TO_ENCRYPT' // 使用RSA公钥进行加密 const encryptedData = encrypt.encrypt(data) // 将加密后的数据发送到后端 // 例如使用axios发送POST请求 axios.post('/api/decrypt', { encryptedData }) .then(response => { console.log(response.data) }) .catch(error => { console.error(error) }) ``` 后端Java解密代码: ```java import org.apache.commons.codec.binary.Base64; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.crypto.Cipher; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; @RestController public class DecryptionController { // 将Base64编码后的私钥字符串转换为PrivateKey对象 private PrivateKey getPrivateKey(String privateKeyStr) throws Exception { byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(keySpec); } @PostMapping("/api/decrypt") public String decryptData(@RequestBody EncryptedData encryptedData) throws Exception { String privateKeyStr = "YOUR_RSA_PRIVATE_KEY"; PrivateKey privateKey = getPrivateKey(privateKeyStr); // 使用私钥进行解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] encryptedBytes = Base64.decodeBase64(encryptedData.getEncryptedData()); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); // 返回解密后的数据 return new String(decryptedBytes, StandardCharsets.UTF_8); } } ``` 创建一个名为 `EncryptedData` 的Java类,用于接收前端传递的加密数据: ```java public class EncryptedData { private String encryptedData; public String getEncryptedData() { return encryptedData; } public void setEncryptedData(String encryptedData) { this.encryptedData = encryptedData; } } ``` 请将 `YOUR_RSA_PUBLIC_KEY` 替换为你的RSA公钥,将 `YOUR_RSA_PRIVATE_KEY` 替换为你的RSA私钥。在前端,你可以使用axios或其他HTTP库发送POST请求到后端的 `/api/decrypt` 路径,并将加密后的数据作为请求体的 `encryptedData` 字段传递。后端将解密后的数据作为响应返回给前端

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值