Vue+Springboot整合RSA加密笔记

   整体思路就是后端Springboot根据jdk自带的RSA创建一个公私钥匙存入工具类中,前端页面点击登录按钮后首先向后端get到公钥,然后使用公钥加密密码向后端POST提交数据,后端接收后先用私钥解密,然后判断数据库能否查询出来同样的数据,存在即返回前端code码。(可以根据自己需要更改数据,工具类代码完全可以全部copy)

参考原文链接springboot中使用RSA加密实现密码信息的密文传输_梅比斯-维维亚米利欧的博客-CSDN博客

附上RSA在线加解密

rsa在线加解密——开发者在线工具,工具猫

目录

一,先写后端,创建一个工具类(可以直接copy)

二,生成公私钥

三,定义前端get获取公钥的方法

四,在controller解码进行其他操作

五,前端所需操作


一,先写后端,创建一个工具类(可以直接copy)

package com.example.demo.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class RSAUtils {
    protected static final Log log = LogFactory.getLog(RSAUtils.class);
    private static String KEY_RSA_TYPE = "RSA";
    private static String KEY_RSA_TYPE_ALL = "RSA/ECB/PKCS1Padding";
    private static int KEY_SIZE = 1024;//JDK方式RSA加密最大只有1024位
    private static int ENCODE_PART_SIZE = KEY_SIZE/8;
    public static final String PUBLIC_KEY_NAME = "public";
    public static final String PRIVATE_KEY_NAME = "private";

    /**
     * 创建公钥秘钥
     * @return
     */
    public static Map<String,String> createRSAKeys(){
        Map<String,String> keyPairMap = new HashMap<>();//里面存放公私秘钥的Base64位加密
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_RSA_TYPE);
            keyPairGenerator.initialize(KEY_SIZE,new SecureRandom());
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            //获取公钥秘钥
            String publicKeyValue = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
            String privateKeyValue = Base64.encodeBase64String(keyPair.getPrivate().getEncoded());

            //存入公钥秘钥,以便以后获取
            keyPairMap.put(PUBLIC_KEY_NAME,publicKeyValue);
            keyPairMap.put(PRIVATE_KEY_NAME,privateKeyValue);
        } catch (NoSuchAlgorithmException e) {
            log.error("当前JDK版本没找到RSA加密算法!");
            e.printStackTrace();
        }
        return keyPairMap;
    }

    /**
     * 公钥加密
     * 描述:
     *     1字节 = 8位;
     *     最大加密长度如 1024位私钥时,最大加密长度为 128-11 = 117字节,不管多长数据,加密出来都是 128 字节长度。
     * @param sourceStr
     * @param publicKeyBase64Str
     * @return
     */
    public static String encode(String sourceStr,String publicKeyBase64Str){
        byte [] publicBytes = Base64.decodeBase64(publicKeyBase64Str);
        //公钥加密
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicBytes);
        List<byte[]> alreadyEncodeListData = new LinkedList<>();

        int maxEncodeSize = ENCODE_PART_SIZE - 11;
        String encodeBase64Result = null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA_TYPE);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(KEY_RSA_TYPE_ALL);
            cipher.init(Cipher.ENCRYPT_MODE,publicKey);
            byte[] sourceBytes = sourceStr.getBytes("utf-8");
            int sourceLen = sourceBytes.length;
            for(int i=0;i<sourceLen;i+=maxEncodeSize){
                int curPosition = sourceLen - i;
                int tempLen = curPosition;
                if(curPosition > maxEncodeSize){
                    tempLen = maxEncodeSize;
                }
                byte[] tempBytes = new byte[tempLen];//待加密分段数据
                System.arraycopy(sourceBytes,i,tempBytes,0,tempLen);
                byte[] tempAlreadyEncodeData = cipher.doFinal(tempBytes);
                alreadyEncodeListData.add(tempAlreadyEncodeData);
            }
            int partLen = alreadyEncodeListData.size();//加密次数

            int allEncodeLen = partLen * ENCODE_PART_SIZE;
            byte[] encodeData = new byte[allEncodeLen];//存放所有RSA分段加密数据
            for (int i = 0; i < partLen; i++) {
                byte[] tempByteList = alreadyEncodeListData.get(i);
                System.arraycopy(tempByteList,0,encodeData,i*ENCODE_PART_SIZE,ENCODE_PART_SIZE);
            }
            encodeBase64Result = Base64.encodeBase64String(encodeData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encodeBase64Result;
    }

    /**
     * 私钥解密
     * @param sourceBase64RSA
     * @param privateKeyBase64Str
     */
    public static String decode(String sourceBase64RSA,String privateKeyBase64Str){
        byte[] privateBytes = Base64.decodeBase64(privateKeyBase64Str);
        byte[] encodeSource = Base64.decodeBase64(sourceBase64RSA);
        int encodePartLen = encodeSource.length/ENCODE_PART_SIZE;
        List<byte[]> decodeListData = new LinkedList<>();//所有解密数据
        String decodeStrResult = null;
        //私钥解密
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateBytes);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_RSA_TYPE);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(KEY_RSA_TYPE_ALL);
            cipher.init(Cipher.DECRYPT_MODE,privateKey);
            int allDecodeByteLen = 0;//初始化所有被解密数据长度
            for (int i = 0; i < encodePartLen; i++) {
                byte[] tempEncodedData = new byte[ENCODE_PART_SIZE];
                System.arraycopy(encodeSource,i*ENCODE_PART_SIZE,tempEncodedData,0,ENCODE_PART_SIZE);
                byte[] decodePartData = cipher.doFinal(tempEncodedData);
                decodeListData.add(decodePartData);
                allDecodeByteLen += decodePartData.length;
            }
            byte [] decodeResultBytes = new byte[allDecodeByteLen];
            for (int i = 0,curPosition = 0; i < encodePartLen; i++) {
                byte[] tempSorceBytes = decodeListData.get(i);
                int tempSourceBytesLen = tempSorceBytes.length;
                System.arraycopy(tempSorceBytes,0,decodeResultBytes,curPosition,tempSourceBytesLen);
                curPosition += tempSourceBytesLen;
            }
            decodeStrResult = new String(decodeResultBytes,"UTF-8");
        }catch (Exception e){
            e.printStackTrace();
        }
        return decodeStrResult;
    }
}

二,生成公私钥

可以在application启动类中直接获取一下,也可以单独写个地方调用

//        生成共私钥
        Map<String, String> rsaKeys = RSAUtils.createRSAKeys();
        String publicKey = rsaKeys.get(RSAUtils.PUBLIC_KEY_NAME);
        System.out.println("publicKey:"+ publicKey);     
        String privateKey = rsaKeys.get(RSAUtils.PRIVATE_KEY_NAME);
        System.out.println("privateKey:"+ privateKey);

三,定义前端get获取公钥的方法

    //引用公钥
    @Value("${publicKey}")
    private String publicKey;
    //引用私钥
    @Value("${privateKey}")
    private String privateKey;

    //前端get获取公钥
    @CrossOrigin
    @GetMapping("api/getPublicKey")
    @ResponseBody
    public String getPublicKey(){
        System.out.print(this.publicKey);
        return this.publicKey;
    }

四,在controller解码进行其他操作

(userpw变量的操作) userpw= RSAUtils.decode(userpw,this.privateKey);

    @CrossOrigin
    @PostMapping(value = "api/login")
    //@ResponseBody返回json格式的结果
    @ResponseBody
    public Result login(@RequestBody User requestUser, HttpSession session) {
        // 对 html 标签进行转义,防止 XSS 攻击
       String username = requestUser.getUsername();
       String userpw=requestUser.getPassword();
       username = HtmlUtils.htmlEscape(username);
        System.out.print(userpw+"1");
       userpw= RSAUtils.decode(userpw,this.privateKey);
        System.out.print(userpw+"2");
       //赋值给User
        User user =userService.get(username,userpw);
        //正常判断service返回的是否为空
        if (null == user) {
            String message = "账号密码错误";
            System.out.println(message);
            return new Result(400,message);
        } else {
            //将用户登录的信息存放到session中
            session.setAttribute("user",user);
            return new Result(200,user.getPassword());
        }
    }

至此后端所需工作已经准备完毕,前端get请求/getPublicKey时获取公钥然后加密post提交给/login,后端在进行解密后的判断。

五,前端所需操作

需要提前引入jsencrypt

npm install jsencrypt --save

<script>
   //引入jsencrypt
  import JSEncrypt from 'jsencrypt';
export default {
  //登录按钮的单击事件login对应的登录方法、
  //methods中可以写方法或函数
  methods: {
    login() {
      var _this = this
      console.log(this.$store.state)
       //向后端get公钥
      this.$axios.get('/getPublicKey').then(res => {
        let publicKey = res.data;
        //判断是否是否成功取到公钥
        if (publicKey) {
          //  onsole.log(this.publicKey)
            //new一个上方引用的jsencrypt
           let encrypt = new JSEncrypt()
            //将公钥存入内
           encrypt.setPublicKey(publicKey)
          this.$axios.post('/login', {
            // post方式向后端传输数据,其地址应是/api/login
            username: this.loginForm.username,
            //这个时候就是直接使用公密加密密码提交给后台
            password: encrypt.encrypt(this.loginForm.password)
          }).then(successResponse => {
            if (successResponse.data.code === 200) {
              sessionStorage.setItem('name', successResponse.data.o)
              // var data = this.loginForm
              _this.$store.commit('login', _this.loginForm)
              var path = this.$route.query.redirect
              this.$router.replace({ path: path === '/' || path === undefined ? '/index' : path })
            } else {
              alert("账号或密码错误");
            }
          })
            .catch(failResponse => {
            })
        } else{
                   this.$message.error('获取公钥失败')
               }
      })
    }
  }
}

</script>
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值