欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RSA+AES加密数据交互,后台java

程序员文章站 2024-03-14 16:04:52
...
  • 问题引出,因为项目需要,要对数据进行安全加密,因为安全力度相对比较高,所以就采用了加密措施,以及https协议

  • 先解释两点,所有的加密,不论是rsa,还是des,还是md5等等,无非是分为两种,一种是对称加密,一种非对称加密,对称加密自然相同秘钥就可逆了,安全性相对来说比较低.

  • 然而,rsa加密的文本长度和秘钥大小有关,2048位秘钥最大可以加密256位文本(不是256位就是128位),而对于大量的数据交互来说,明显不符合要求,AES可以加密较大文本,然而上面说了,安全性不达标.

  • 因此鉴于以上两点,决定采用RSA+AES,先说设计思路

    1. 因为AES可逆,所以,AES的秘钥就不能固定不变,应该每次交互数据秘钥都不一样
    2. 如果要实现1的条件,则秘钥必须作为额外的数据参数,不断的前后端交互传递
    3. 如果要实现2,则秘钥必须不能明文,并且秘钥安全性必须极高,否则,加密等于没加密
    4. 如果要实现3.则rsa是一个很好的选择
    5. 如果要实现4,则应该有2对rsa秘钥,客户端一对,服务端一对,彼此交互公钥,注意,不能交换私钥,因为有了私钥,则就等于有了公钥,所以,应该是2对秘钥,彼此交换公钥,客户端使用服务端公钥加密,服务端用服务端私钥解密,服务端使用客户端私钥加密,客户端使用服务端公钥解密
  • 因此,鉴于以上条件,客户端有公共请求体必须是:

    {
    	key:"使用服务端公钥加密之后的字符串",
    	data:"使用AES加密之后的字符串"	
    }
    
  • 好像说的废话比较多,下面进入正题:

  • RSAUtil
    使用npm install jsencrypt --save,安装插件

import JSEncrypt from 'jsencrypt'
import Constans from '../constants'

export default {
    encrypt:function (val) {
        var jsencrypt = new JSEncrypt();
        jsencrypt.setPublicKey(Constans.RSA.PUBLIC.PREFIX+Constans.RSA.PUBLIC.KEY+Constans.RSA.PUBLIC.SUFFIX);
        return jsencrypt.encrypt(val);
    },
    decrypt:function (val) {
        var jsdecrypt = new JSEncrypt();
        jsdecrypt.setPrivateKey(Constans.RSA.PRIVATE.PREFIX+Constans.RSA.PRIVATE.KEY+Constans.RSA.PRIVATE.SUFFIX);
        return jsdecrypt.decrypt(val);
    }
}
  • AESUtil
    npm install crypto-js --save
const CryptoJS = require('crypto-js');

export default {
    encrypt: function (val, key) {
        return CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(val),CryptoJS.enc.Utf8.parse(key),{
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        }).ciphertext.toString().toUpperCase();
    },
    decrypt: function (val, key,) {
        return CryptoJS.AES.decrypt(CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(val)),CryptoJS.enc.Utf8.parse(key),{
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        }).toString(CryptoJS.enc.Utf8).toString();
    }
}

  • 因为客户端的所有请求都要进行上述所说的加密处理,所以,一个地方用下,加密下,太麻烦,所以,我进行了请求拦截封装
import axios from 'axios'
import {MessageBox, Message} from 'element-ui'
import store from '@/store'
import {getToken} from '@/utils/auth'
import StringUtil from '@/utils/StringUtil'
import RSAUtil from '@/utils/RSAUtil'
import AESUtil from '@/utils/AESUtil'

const baseUrl = 'http://localhost:8081/';

// create an axios instance
const service = axios.create({
    //baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
    baseURL: baseUrl,
    withCredentials: true, // send cookies when cross-domain requests
    timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
    config => {
        // do something before request is sent
        var temp = config.data;
        // 生成随机的32位字符串,高防java uuid
        var key = StringUtil.guid_();
        console.log("key : "+key)
        // 对key进行rsa加密
        var key_ = RSAUtil.encrypt(key);
        // 对数据进行aes加密
        var data_ = AESUtil.encrypt(JSON.stringify(temp),key);
        console.log('data : '+data_)
        // 放入要提交的数据中
        config.data = {
            key: key_,
            data: data_
        }
        console.log(JSON.stringify(config.data))

        if (store.getters.token) {
            // let each request carry token
            // ['X-Token'] is a custom headers key
            // please modify it according to the actual situation
            config.headers['ACCESS-TOKEN'] = getToken()
        }

        console.log(config);
        if (config.method.toLocaleUpperCase() == 'POST'||config.method.toLocaleUpperCase()=='PUT'){
            config.headers['Content-Type'] = "application/json;charset=utf-8"
        }
        return config
    },
    error => {
        // do something with request error
        return Promise.reject(error)
    }
)

// response interceptor
service.interceptors.response.use(
    /**
     * If you want to get http information such as headers or status
     * Please return  response => response
     */

    /**
     * Determine the request status by custom code
     * Here is just an example
     * You can also judge the status by HTTP Status Code
     */
    response => {
        const res = response.data

        // if the custom code is not 20000, it is judged as an error.
        if (res.code !== '0000') {
            Message({
                message: res.message || 'error',
                type: 'error',
                duration: 5 * 1000
            })

            // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
            if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
                // to re-login
                MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
                    confirmButtonText: 'Re-Login',
                    cancelButtonText: 'Cancel',
                    type: 'warning'
                }).then(() => {
                    store.dispatch('user/resetToken').then(() => {
                        location.reload()
                    })
                })
            }
            return Promise.reject(res.message || 'error')
        } else {
            var key = RSAUtil.decrypt(res.key);
            var data = JSON.parse(AESUtil.decrypt(res.data),key);
            return data;
        }
    },
    error => {
        Message({
            message: error.message,
            type: 'error',
            duration: 5 * 1000
        })
        return Promise.reject(error)
    }
)

export default service

  • 如上,我们就可以直接调用传入原始对象了,会统一加密处理,解密也统一处理,在发起请求的时候不用关心加密和解密操作,可以解放许多新手不懂,这样项目进度也比较快
  • 以上都是前端代码,后台代码同样会面临每次加解密问题,所以,也做了封装
  • RSAUtil(java)
package com.zpecs.blog.utils.rsa;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
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.Properties;

public class RSAUtil {
    public static String CLIENT_PUB_KEY = null;
    public static String SERVER_PUB_KEY = null;
    public static String SERVER_PRI_KEY = null;

    static {
        try (InputStream is = RSAUtil.class.getClassLoader().getResourceAsStream("rsa.properties")) {
            Properties properties = new Properties();
            properties.load(is);
            CLIENT_PUB_KEY = properties.getProperty("clintPublicKey");
            SERVER_PUB_KEY = properties.getProperty("serverPublicKey");
            SERVER_PRI_KEY = properties.getProperty("serverPrivateKey");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    //private static Map<Integer, String> keyMap = new HashMap<Integer, String>();  //用于封装随机产生的公钥与私钥

    public static void main(String[] args) throws Exception {
        //生成公钥和私钥
/*        String[] keys = genKeyPair();
        System.out.println("公钥 : \n"+keys[0]);
        System.out.println(keys[0].length());
        System.out.println("私钥 : \n"+keys[1]);
        System.out.println(keys[1].length());
        //加密字符串
        String message = "df7238201111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
        System.out.println("待加密源 : \n" + message);
        //System.out.println();
        String s0 = encryptPublic(message, keys[0]);
        System.out.println("公钥加密之后 : \n" + s0);
        System.out.println("私钥解密之后 : \n" + decryptPrivate(s0, keys[1]));
        String s1 = encryptPrivate(message, keys[1]);
        System.out.println("私钥加密之后 : \n" + s1);
        System.out.println("公钥解密之后 : \n" + decryptPublic(s1, keys[0]));*/
        String s = "HlDD2Ca1hh8kc5ldtHqEmWMxT8OZsRAOpwR+4mVbINH/90+1KeEbDUFIf5O/benxOixcwt3CAnRkWJ22HbiOshf2GNhd82kGLIOH0it8FeoWPUnTok56y0JVqL3VxxCSDYWWlHfdNEDHa2lkVADJcWkyrQgqd2ea00+KvBpSvxPLMoLpuBA2c0JKckXgLqIKDR/wqtFgg5jg/kVTm3JJrRyYKLz2e0p/PNlrENNuMw8GG2+DEIRV/KzJPZ69FJKuyVNvInfnYa/ZTLUmzcn9RjP6DgvXShMwJnBuQ2IaTPX0FhhQ8OkEGJMiNIveb8MEsDQGFQ4EZHyIm6HWw9zUDA==";
        System.out.println(decryptPrivate(s,
                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCQJ3kWiz3y2fivl3l1dAStBRRwk6vTK6u9oroOD9YIqrSccmh94Ou+Wbvz8TQBwtSGPZcNSJhqQUSPr75HygBJRhRGrNJSO8C6M4NuYKsGz8YP3EcTlZndA55Vfrx0uZdEmOYXUtUtb3IbirWS2WiIhJItu6mSWiJyzVri2sVTthhlB+qaRVoLrki0K7XCHBtFyKQHf22rB5d+dAP3jg3h9NoG+CmOV9h2TT2ujTH5HPJ/AU62ijasSIwlM6z7Agi2F52E8UUGpD5kTIz94H2AlhXtZ/1FPfHQzTo5UoNAEV33QcVuC7A4dxuCUObEKoFZoTlyv7wNSSw8NIfOIugVAgMBAAECggEAPLMiXcfMEhKOkQGrdzWfMmvNK4pC8+yTqIp45artaUDYRHg4X6jyG3kVl6adS5CKhOwySrmi1Dsfb5GFAh2g+Tm1F/11ooLeqIlAcp3p5jhfIhaTJz/7RgFcDowLNutfMtdfK7sJYNRorAhAZNF/Ht0T4IYA5Utm7ghimNud8506etpj84j8VbFeDGX89gOrWHGwKNeGFxaHQaIIZIwuqTtlmoIa2QRTtnVuFwshqTYwO+zCE6kqgivnmoiAMIxWWvxiKOA5LWdqhDoaTCj2P8ae19ZEpYz99Yb7Lx2efcHB1OYPAI/JSORURAEG5VjF0T3UyAv4SlsaCHRqkMGWEQKBgQDbX4Q7pIrRy96Y5+AobjuLPQKfAu5gWZ2XX88ktT7ZjCk79hbWM/aWPmPxbZq4rLHvAnryr9kZASuRgkZwpgbqHyQAhf2mZ5jmCBGSQPnB3wO3F6reyuh4kkkQVDR3o46nS5t2OKI+15SfMCpfwYmYafiL0FB9JiBEjnLyQCXV2wKBgQCoOO+2ZoZS+eLfk0L3wAAqP8sY/rToOVz0R/gVfDpSFOnezLe3XTUrQrLk6COiQuIJ9eRenqa+Mt1cieptaiB/CV0Y68hMAaGz5/gNazLtkfEUczW2NZjKOZwESUxgewA2cRiZb2JNHmlSM5l+miOIoBFpfSwdyDfkfd2b45e0zwKBgAmOfK04es+u6PCSUWKRgsiLDN0ufIH4BXR9uQFpX+aMQ5OYIeCM/PYIm8P9uVrIMywtWHvQC04ajfJV0YnAwdZbKu9W5vjj1HZY7aMIb5jxhTDpuAjioAP4o3QxpuN7XZCOK6SXzQGd1JymtYHcZYkdPLWiio8ZJRi3d+xzvPI3AoGAYar88ifAYTiYEjqLrRAaiG0VW+O14QY9A88tKDxCGBnwVt0A5UMGdaF6ABEPb0vptOLAvnbaVJ9viiTAqNnvGBK1rJxoZEimO6+4gwH0RZ5wG/FwA+RGW1LrVEnCQFnpm7I6GAtlRWUcvQ8cVTbk3pQgx+BW1svCN7UkDzgqgl0CgYEA2oFUkm5IpHbxvMkklplwI6KvbaF+aXGWgEZNvNnI5dYTcjwc9gJRlXlAwo/g+ImEg5l/drKijQUYcgiKozGIU0cZRBIBO26TUFPmqGmWnIREBrxNyLzDqkRKriM8muu7HWjIflCSzBXIO5BcQxTQWDvnsvSU3U6E/73O7pWZ2zw="));
        //System.out.println(encryptPrivate("df723820","MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDV9OCyNmLz9QDqE+vGTQovEByeAldqDdlx9C/1W6d5mdo0pd/rIowlD7tgZgqdbOdytgdd4VTFdAczY8yghUIa/ni2dSZeWrYpST6kRyh/WFOO9Vegq+PJzwo4nnFSHTsSePQ4qX+W5ZBGmxZvn8jaCtXdqhF4gx2LhTKKZ4663qtsgy+WYlP+zCfeh6Czo6l5lYfge4+zhgLR6aUWwO3jTHwQswCOwNlSLaO8KhkXf4TPN23V2aB22FV2fHY9dxZuZPxVqMLyX5ccGkS26PeGUbwnI/7nqvq+J1Wk8/Wi6eEqCz9SU1JflrKcrInSEietUkDACnwvIaYQT/gHdoVTAgMBAAECggEAGUxECS5fEuNkQUkrtp3DV387Mv+p4FNU46Fwzj0RF1K2t0Tprf6+vV8X07UdCjInR6v4QQR0pogqlcv2FQDMqS5vjXtalwt4wHb1niz/v9bswlmGC+xnGaSOW9V4JrJoGq4MimqYOHpaTc7mnzowYH+pe/Uw7aPrKWUNbcoC2VtlYbXrHuL/wUpqffFK1cqtndQ7yPCJzWS71msffRxpZES5ujUw5BL53FbfoczIonpH0r2IYwWIUO5KxtUvupZxXdr1BjUauHHI9vMwkeG3mstVnz6W/q1xA34o7KhHIXW7SMjA+uIIdtn1ElE6To1o6SI6CzqCGDHnH2qOFqaCMQKBgQDwpH7CKEodyGveMpwS2NoK0Yqf9ppGcDhDCMKS26TgVJ4IG1jyRtLXMlzBZ3pJY79BA4rWSbY0B3D1SDmcJJP1ixOBgFDznnIdv9dUUM4C61TDFXOkQSgcfEeAThYLpX0/OLjj7+SEhYbnp58mF96S1G0wF218IvV7LPfAK7KqCwKBgQDjnGYwJ1wDuRiSmrcZdtXL9zxwvsG2ODgA5U0Q98BcKWuvsM2/FWvYuBcN+5tIAzToJs9ohKRJss+ugZSZSXpv7zvYScrg4ph9mQsn/zhXiGx1GiOkxorOohqf5Gvx7Wf7nqm/EVPmog0FMQlnkR0JBMu4XrmywHxnGmTjNkxm2QKBgQDfKw5LLWYe3MH8nN7VM7pykgWHeAF3FZd3w2X/ICd1y8OLLSF9/mSGIjSXQEnOSe0SdCCLvmx1L/l33/VdcyasbsA2NzPb2rNmF4Wwsgd7+ZbwHLLUP4DdefwtZz1Wq7DNsuL0sIMyy0pjB7a2cyh87vgbw35Lw3f5NajF1UCqJQKBgE9Z90ZScoHZxfdWeP8nruGtECU+W8prTxsA1h1UQnve9OwLd69miHLFu0Pks/4nIArPfP+zPpNzA3STOHs4YrcjcHm3QEOmvAMNmBYZpErgBO/ObR7FGR9w5FdaC0gMvHO8nPE/2UBOvrtQnTa+IKFESsG8RIFNGhHX4dRU2c4BAoGAL3TlLNAOtVU7xzQhi0e3wsneUC+08axWVpudZpTkkuAwvGVw+ZbG2tb9nF/oApbgVskNptP9M9K8VPLhgbplB6hfvvI/OrKRpyWib73RK8y98g/tRvd+vQWqfetnCeY63r1deBKnxCdwmBxKr+Svg+RTx7tggIYp6BAJzWVwWP8="));
    }

    /**
     * 随机生成**对
     *
     * @throws NoSuchAlgorithmException
     */
    public static String[] genKeyPair() {
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化**对生成器,**大小为96-1024位
            keyPairGen.initialize(2048, new SecureRandom());
            // 生成一个**对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥


            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
            String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
            // 将公钥和私钥保存到Map
            return new String[]{publicKeyString, privateKeyString};
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * RSA公钥加密
     *
     * @param str       加密字符串
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 加密过程中的异常信息
     */
    public static String encryptPublic(String str, String publicKey) {
        try {
            //base64编码的公钥
            byte[] decoded = Base64.decodeBase64(publicKey);
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            //RSA加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
            return outStr;
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * RSA私钥解密
     *
     * @param str        解密字符串
     * @param privateKey 私钥
     * @return 铭文
     * @throws Exception 解密过程中的异常信息
     */
    public static String decryptPrivate(String str, String privateKey) {
        try {
            //64位解码加密后的字符串
            byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
            //base64编码的私钥
            byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(
                    decoded));
            //RSA解密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            String outStr = "";
            outStr = new String(cipher.doFinal(inputByte));
            return outStr;
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * rsa 私钥加密
     *
     * @param str
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String encryptPrivate(String str, String privateKey) {
        try {
            //base64编码的公钥
            byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(
                    decoded));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
            return outStr;
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * rsa 公钥解密
     *
     * @param str
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String decryptPublic(String str, String publicKey) {
        try {
            //64位解码加密后的字符串
            byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
            //base64编码的私钥
            byte[] decoded = Base64.decodeBase64(publicKey);
            RSAPublicKey priKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            //RSA解密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            String outStr = new String(cipher.doFinal(inputByte));
            return outStr;
        } catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

  • AESUtil(java)
package com.zpecs.blog.utils.aes;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

public class AESUtil {
        private static String Algorithm         = "AES";
        private static String AlgorithmProvider = "AES/ECB/PKCS5Padding"; // 算法/模式/补码方式

        public static byte[] encrypt(String src, byte[] key) {
            try {
                SecretKey secretKey = new SecretKeySpec(key, Algorithm);
                Cipher cipher = Cipher.getInstance(AlgorithmProvider);
                cipher.init(Cipher.ENCRYPT_MODE, secretKey);
                byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
                return cipherBytes;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        public static String encrypt(String src, String key) {
            try {
                return byteToHexString(encrypt(src,key.getBytes("utf-8")));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        public static byte[] decrypt(String src, byte[] key) {
            try {
                SecretKey secretKey = new SecretKeySpec(key, Algorithm);
                Cipher cipher = Cipher.getInstance(AlgorithmProvider);
                cipher.init(Cipher.DECRYPT_MODE, secretKey);
                byte[] hexBytes = hexStringToBytes(src);
                byte[] plainBytes = cipher.doFinal(hexBytes);
                return plainBytes;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        public static String decrypt(String src, String key) {
            try {
                return new String(decrypt(src, key.getBytes("utf-8")),"utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        /**
         * 将byte转换为16进制字符串
         *
         * @param src
         * @return
         */
        public static String byteToHexString(byte[] src) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < src.length; i++) {
                int v = src[i] & 0xff;
                String hv = Integer.toHexString(v);
                if (hv.length() < 2) {
                    sb.append("0");
                }
                sb.append(hv);
            }
            return sb.toString();
        }

        /**
         * 将16进制字符串装换为byte数组
         *
         * @param hexString
         * @return
         */
        public static byte[] hexStringToBytes(String hexString) {
            hexString = hexString.toUpperCase();
            int length = hexString.length() / 2;
            char[] hexChars = hexString.toCharArray();
            byte[] b = new byte[length];
            for (int i = 0; i < length; i++) {
                int pos = i * 2;
                b[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
            }
            return b;
        }

        private static byte charToByte(char c) {
            return (byte) "0123456789ABCDEF".indexOf(c);
        }
}

  • 基本请求体,为了解决每次解密问题
package com.zpecs.blog.pojo.req;

import com.alibaba.fastjson.JSON;
import com.zpecs.blog.utils.aes.AESUtil;
import com.zpecs.blog.utils.rsa.RSAUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.io.Serializable;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class BaseRequest implements Serializable {
    private String key;
    private String data;

// 获取解密之后的对象
    public<T> T getObj(Class<T> clazz){
        // 对key rsa解密
        String key_ = RSAUtil.decryptPrivate(key, RSAUtil.SERVER_PRI_KEY);
        // 对数据进行aes解密
        String data_ = AESUtil.decrypt(data, key_);
        // 进行json解析
        return JSON.parseObject(data_,clazz);
    }
}

  • 基本响应体
package com.zpecs.blog.pojo.res;

import com.alibaba.fastjson.JSON;
import com.zpecs.blog.exceptions.BaseException;
import com.zpecs.blog.utils.StringUtil;
import com.zpecs.blog.utils.aes.AESUtil;
import com.zpecs.blog.utils.rsa.RSAUtil;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.UUID;

@Getter
@Setter
public class BaseResponse implements Serializable {
    private String code;
    private String msg;
    private String data;
    private String key;

    private BaseResponse() {

    }

    public static BaseResponse success() {
        BaseResponse response = new BaseResponse();
        response.code = BaseException.ExceptionType.SUCCESS.getCode();
        response.msg = BaseException.ExceptionType.SUCCESS.getMsg();
        return response;
    }

    public static BaseResponse success(Object data) {
        BaseResponse response = success();
        // aes key
        String key = UUID.randomUUID().toString().replaceAll("-", "");
        // 对key进行rsa加密
        response.key = RSAUtil.encryptPublic(key, RSAUtil.CLIENT_PUB_KEY);
        // 对内容进行aes加密
        response.data = AESUtil.encrypt(JSON.toJSONString(data), key);
        return response;
    }

    public static BaseResponse error(BaseException.ExceptionType exceptionType) {
        BaseResponse baseResponse = new BaseResponse();
        baseResponse.code = exceptionType.getCode();
        baseResponse.msg = exceptionType.getMsg();
        return baseResponse;
    }

    public static BaseResponse error(BaseException.ExceptionType exceptionType, Object data) {
        BaseResponse baseException = error(exceptionType);
        String key = StringUtil.uuid();
        // 对key进行rsa加密
        baseException.key = RSAUtil.encryptPublic(key, RSAUtil.CLIENT_PUB_KEY);
        // 对内容进行aes加密
        baseException.data = AESUtil.encrypt(JSON.toJSONString(data), key);
        return baseException;
    }
}

  • 如此,基本就完美解决客户要求,并且,对于新手开发来说没有太大压力,因为整个开发过程和之前不加密的开发过程几乎一模一样
  • 例子:
    1.前端请求:
export function login(data) {
    return request({
        url: 'api/account/login',
        method: 'post',
        data
    })
}

login({username:'zhangsan',password:'123'}).then(data => {
                            console.log(data);
                            _v.loading = false;
                        },error => {
                            _v.loading = false;
                        })
  1. 后台接口
@RestController
@RequestMapping("api/account")
public class AccountController {
    @Reference
    private UserService   userService;
    @Autowired
    private RedisTemplate redisTemplate;

    @PostMapping(value = "login",consumes = "application/json")
    public BaseResponse login(@RequestBody BaseRequest request) {
        String accessToken = StringUtil.uuid();
        UserModel userModel = userService.login(request.getObj(UserModel.class));
        redisTemplate.opsForValue().set(Constans.RedisKey.ACCESS_TOKEN_PREFIX + userModel.getUsername(), accessToken);
        return BaseResponse.success(new HashMap() {{
            this.put("ACCESS-TOKEN", accessToken);
            this.put("currentUser", userModel);
        }});
    }
}
  • 代码入侵性极小,并且就算突然移除加密,完全不影响已有代码逻辑