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

  • 问题引出,因为项目需要,要对数据进行安全加密,因为安全力度相对比较高,所以就采用了加密措施,以及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 keyMap = new HashMap();  //用于封装随机产生的公钥与私钥

    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 getObj(Class 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);
        }});
    }
}
  • 代码入侵性极小,并且就算突然移除加密,完全不影响已有代码逻辑

你可能感兴趣的:(RSA,AES,服务器,JS,客户端)