java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot Vue 身份认证加密

Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现过程

作者:徐州蔡徐坤

RSA是一种非对称加密算法,适用于用户身份认证加密,本文介绍了基于RSA的用户身份认证加密机制的实现,包括前端Vue.js使用jsencrypt库对用户名密码进行加密,后端使用RSA私钥解密验证用户凭据,感兴趣的朋友跟随小编一起看看吧

Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现

什么是RSA?

RSA算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥,一个是公钥,一个是私钥

RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制

在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK

正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要

安全需求介绍

背景:在安全扫描过程中,系统被检测到存在中危漏洞,影响了用户登录环节的信息安全性

漏洞描述

Web程序在处理用户登录过程中,针对用户名和口令在传输前未采用加密。用户名和口令一旦被恶意攻击者嗅探或暴力破解得到后,可以直接利用它去登录系统。

解决方案:建议对用户名、口令等参数值采用强加密算法,如SHA512、RSA、AES、国密算法等,避免使用MD5、Base64、DES、3DES等弱算法。

问题分析:未加密的敏感信息在传输过程中易被拦截,尤其是在公共网络环境下。这使得系统的认证机制成为攻击目标,存在较高的安全隐患

需求实现

前后端交互流程

基于RSA加密的登录流程,Web端和服务端的交互过程详细步骤:

  1. 用户发起登录请求
  1. 服务端返回公钥
  1. Web端加密用户凭据
  1. 服务端解密并验证
  1. 返回登录结果
  1. Web端处理响应

前端使用 RSA 加密密码

在前端 Vue.js 中,使用 jsencrypt 库对用户名密码进行加密,并将加密后的用户名密码发送给后端

安装 jsencrypt库

在Vue.js 项目中运行以下命令来安装 jsencrypt

npm install jsencrypt --save

实现敏感信息加密

在 Vue.js 登录页面中,对敏感信息进行加密,然后发送给后端:

// 引入 jsencrypt 和 Base64 编码库
import JSEncrypt from 'jsencrypt';
// 需要安装 js-base64 库
import { Base64 } from 'js-base64'; 
export default {
  data() {
    return {
      username: '', // 用户输入的用户名
      password: ''  // 用户输入的密码
    };
  },
  methods: {
    /**
     * 使用 RSA 公钥加密字符串
     * @param {string} str - 需要加密的字符串
     * @returns {string|null} - 加密后的字符串,若失败返回 null
     */
    encryptString(str) {
      // 初始化 JSEncrypt
      const encrypt = new JSEncrypt();
      // 设置公钥
      const publicKey = `
        -----BEGIN PUBLIC KEY-----
        ...公钥内容...
        -----END PUBLIC KEY-----
      `;
      encrypt.setPublicKey(publicKey);
      // 加密字符串并返回加密结果
      return encrypt.encrypt(str);
    },
    /**
     * 用户登录逻辑
     */
    login() {
      // 获取用户输入的用户名和密码
      const username = this.username.trim(); // 去除多余空格
      const password = this.password.trim();
      // 验证用户名和密码是否为空
      if (!username || !password) {
        this.$message.error('用户名或密码不能为空'); // 提示用户
        return;
      }
      // 加密用户名和密码
      const encryptedUsername = this.encryptString(username);
      const encryptedPassword = this.encryptString(password);
      // 验证加密是否成功
      if (!encryptedUsername || !encryptedPassword) {
        this.$message.error('加密失败,请检查公钥配置');
        return;
      }
      // Base64 编码的主要作用是将加密后的数据转换成由可见 ASCII 字符组成的字符串,以便在网络传输或存储时避免因特殊字符引发的兼容性问题
      const base64EncodedUsername = Base64.encode(encryptedUsername);
      const base64EncodedPassword = Base64.encode(encryptedPassword);
      // 发送登录请求到后端
      this.$axios.post('/api/login', {
        username: base64EncodedUsername, // 加密后的用户名
        password: base64EncodedPassword  // 加密后的密码
      }).then(response => {
        // 登录成功后的处理逻辑
        if (response.data.success) {
          this.$message.success('登录成功');
          // 跳转到主页面或其他逻辑
        } else {
          this.$message.error(response.data.message || '登录失败');
        }
      }).catch(error => {
        // 请求失败的处理逻辑
        console.error('登录请求失败:', error);
        this.$message.error('登录失败,请稍后重试');
      });
    }
  }
};

服务器端生成RSA的公私钥文件

Windows环境 生成rsa的公私钥文件

安装 OpenSSL:下载并安装 OpenSSL for Windows,可以从 OpenSSL 官网 下载适合的版本。

image-20241120105453452

生成 RSA 私钥

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

  1. 生成 RSA 公钥
openssl rsa -pubout -in private_key.pem -out public_key.pem

Linux环境 生成rsa的公私钥文件

使用RSA算法生成pem格式的私钥文件,指定密钥长度2048

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

使用RSA算法在上述私钥文件基础上生成pem格式的公钥文件

openssl rsa -pubout -in private_key.pem -out public_key.pem

执行完成后,会看到输出两份文件 private_key.pem, public_key.pem。

后端代码实现

返回给前端的公钥接口

将生成的两份密钥文件放入指定的目录中,然后在配置文件中配置公私钥文件所属路径

 /**
     * 获取公钥
     */
    @GetMapping("/getPublicKey")
    public AjaxResult getPublicKey() {
        // 加载资源
        File file = new File("公钥的文件所属路径");
        if (!file.exists()) {
            throw new BusinessException("未获取到指定公钥文件");
        }
        String publicKey;
        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
            publicKey = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
        } catch (IOException e) {
            log.error("读取公钥文件失败", e);
            // 返回错误信息
            return AjaxResultGenerator.error("读取公钥文件失败");
        }
        // 检查 publicKey 是否为 null 或空字符串
        if (publicKey == null || publicKey.isEmpty()) {
            return AjaxResultGenerator.error("公钥内容为空");
        }
        // 删除PEM格式的头部和尾部以及所有空格、换行符
        publicKey = publicKey.replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "")
                .replaceAll("\\s+", "");
        return AjaxResultGenerator.success(publicKey);
    }

解密前端传入的加密字符串

前端的账户和密码进行rsa加密并且base64编码后,调用正常登录接口login()readPrivateKeyAndDecode()方法将 RSA 加密并 Base64 编码的字符串解码后,再用 RSA 私钥对解码后的数据进行解密,最终返回解密后的原始数据

pom.xml

<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.8.26</version>
</dependency>

登录和解密方法

 /**
     * 用户名密码登录
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/v1/login")
    public AjaxResult login(@RequestBody LoginBody loginBody) {
        // 使用 RSA 私钥解密
        String username = readPrivateKeyAndDecode(loginBody.getUsername());
        String password = readPrivateKeyAndDecode(loginBody.getPassword());
        loginBody.setUsername(username);
        loginBody.setPassword(password);
 	    // 执行正常的登录逻辑...
        return AjaxResultGenerator.success();
    }
    /**
     * 读取私钥并解密
     *
     * @param rsaEncoded64Str 已rsa加密并且base64编码后的字符串
     * @return
     */
    public String readPrivateKeyAndDecode(String rsaEncoded64Str) {
        // 加载资源
        File file= new File("私钥的文件所属路径");
        if (!file.exists()) {
            throw new BusinessException("未获取到指定私钥文件");
        }
        String privateKey;
        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
            privateKey = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
        } catch (IOException e) {
            log.error("读取私钥文件失败", e);
            throw new BusinessException("读取私钥文件失败:" + e.getMessage());
        }
        if (StringUtils.isBlank(privateKey)) {
            throw new BusinessException("私钥内容为空");
        }
        // 删除PEM格式的头部和尾部以及所有空格、换行符
        privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");
        // 进行base64解密
        String decodedUsername = new String(Base64.getDecoder().decode(rsaEncoded64Str));
        // 使用 RSA 私钥解密,用到了hutool-all中的类
        return new RSA(privateKey, null)
                .decryptStr(decodedUsername, KeyType.PrivateKey);
    }

实现效果

到此这篇关于Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现的文章就介绍到这了,更多相关Spring Boot Vue 身份认证加密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文