Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
- 什么是RSA?
- 安全需求介绍
- 前后端交互流程
- 前端使用 RSA 加密密码
- 安装 jsencrypt库
- 实现敏感信息加密
- 服务器端生成RSA的公私钥文件
- Windows环境 生成rsa的公私钥文件
- Linux环境 生成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端和服务端的交互过程详细步骤:
-
用户发起登录请求:
-
用户在Web端输入登录操作,Web端开始处理登录流程
-
Web端向服务端发送一个请求,要求获取RSA加密所需的公钥
-
-
服务端返回公钥:
- 服务端接收到公钥请求后,从系统中读取公钥信息,并将公钥发送回Web端。这个步骤的响应无需校验
-
Web端加密用户凭据:
-
Web端使用获取到的公钥,对用户的用户名和密码进行加密。加密后的数据用于安全传输,避免敏感信息在网络中被截获
-
Web端将加密后的用户名和密码通过HTTPS协议发送给服务端。HTTPS协议提供了额外的安全层,防止中间人攻击
-
-
服务端解密并验证:
- 服务端接收到加密的数据后,使用私钥对加密内容进行解密。私钥是严格保密的,只在服务端保存和使用
- 服务端对解密后的用户名和密码进行验证,检查凭据是否正确并符合登录要求
-
返回登录结果:
- 服务端验证完成后,将登录验证的结果返回给Web端。结果可以是登录成功或失败的信息
-
Web端处理响应:
- 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) {// 初始化 JSEncryptconst 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 官网 下载适合的版本。
-
生成 RSA 私钥:
-
在安装目录的bin目录下面,打开命令提示符(
cmd
) -
运行以下命令生成一个2048位的私钥文件
private_key.pem
:openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
-
-
生成 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 基于 RSA 的用户身份认证加密机制实现 什么是RSA?安全需求介绍前后端交互流程前端使用 RSA 加密密码安装 jsencrypt库实现敏感信息加密 服务器端生成RSA的公私钥文件Windows环境 生成rsa的公私钥文件Linux环境 生成rsa的公私钥文件 后端代码实现返…...
Docker搭建有UI的私有镜像仓库
Docker搭建有UI的私有镜像仓库 一、使用这个docker-compose.yml文件: version: 3services:registry-ui:image: joxit/docker-registry-ui:2.5.7-debianrestart: alwaysports:- 81:80environment:- SINGLE_REGISTRYtrue- REGISTRY_TITLEAtt Docker Registry UI- DE…...
Qt打开文件对话框选择文件之后弹出两次
项目场景: 在 Qt 中,使用 ui 自动生成的 UI 文件会为每个控件自动生成一些默认的槽函数。如果您手动创建的槽函数名称与这些自动生成的槽函数名称相同,就会导致信号被多次连接,从而引发多次弹出文件对话框的问题。 原因分析&…...
【JAVA】正则表达式中的正向肯定预查
在Java中,正向肯定预查(Positive Lookahead)是一种正则表达式的高级特性,用于在匹配某个模式之前检查某个条件是否满足。正向肯定预查不会消耗字符,也就是说,它不会将匹配的字符从剩余的字符串中移除&#…...
django从入门到实战(一)——路由的编写规则与使用
Django 路由的编写规则与使用 在 Django 中,路由(URLconf)是将 URL 映射到视图函数的机制。它允许我们定义网站的 URL 结构,并将请求分发到相应的处理函数。以下是关于 Django 路由的定义规则及使用的详细介绍。 1. Django 的路…...
vue框架开发的前端项目,build和package的区别
在使用 Vue 框架开发前端项目时,build 和 package 是两个常见的操作,它们有不同的目的和作用。下面是它们的区别: 1. Build(构建) build 是将前端源代码(如 Vue 组件、JavaScript 文件、CSS 样式等&#…...
视频智能分析软件LiteAIServer摄像机实时接入分析平台噪声监测算法介绍
在视频监控领域,噪声问题一直是一个令人头疼的难题。无论是低光环境、摄像机传感器的高灵敏度,还是编码压缩过程中的失真,都可能导致视频中出现噪声,从而影响监控画面的清晰度和准确性。这些噪声不仅降低了视频的可读性࿰…...
鸿蒙UI开发与部分布局
UI开发 1. 布局概述 1.1 开发流程 1.先确定开发流程 -> 2.分析页面元素构成 ->3.选用合适的布局容器组件 1.3 布局元素组成:盒模型 2.1 布局分类 2.1 线性布局 线性布局是开发中最常用、最基础的布局,通过线性容器Row和Column构建 2.1.1 线性布…...
redis的map底层数据结构 分别什么时候使用哈希表(Hash Table)和压缩列表(ZipList)
在Redis中,Hash数据类型的底层数据结构可以是压缩列表(ZipList)或者哈希表(HashTable)。这两种结构的使用取决于特定的条件: 1. **使用ZipList的条件**: - 当Hash中的数据项(即f…...
css水平居中+垂直居中
display:“flex”,position: “absolute”,top:“50%”,left:“50%”,transform: ‘translate(-50%, -50%)’...
设计模式之 组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它通过将对象组合成树形结构来表示“部分-整体”层次。组合模式允许客户端统一处理单个对象和对象集合。换句话说,组合模式让客户端可以像处理单个对象一样处理对象的集合&#…...
LCR 001 两数相除
一.题目: . - 力扣(LeetCode) 二.原始解法-超时: class Solution: def divide(self, a: int, b: int) -> int: # 1)分析: # 除法计算,不能使用除法符号,可以理解为实现除法 # 除法…...
数据库、数据仓库、数据湖、数据中台、湖仓一体的概念和区别
数据库、数据仓库、数据湖、数据中台和湖仓一体是数据管理和分析领域的不同概念,各自有不同的特点和应用场景。以下是它们的主要区别: 1. 数据库(Database) 定义:结构化的数据存储系统,用于高效地存储、检…...
vue 的生命周期函数
Vue 生命周期函数(生命周期钩子)是 Vue 实例从创建到销毁过程中,不同阶段所触发的特定函数。理解这些生命周期函数对于开发 Vue 应用至关重要,因为它们让你在不同的生命周期阶段执行代码,比如数据初始化、DOM 渲染完成…...
单片机UART协议相关知识
概念 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器) 是一种 异步 串行 全双工 通信协议,用于设备一对一进行数据传输,只需要两根线(TX,RX)。 异步&…...
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
前言 大家好吖,欢迎来到 YY 滴 操作系统不挂科 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 本博客主要内容,收纳了一部门基本的操作系统题目,供yy应对期中考试复习。大家可以参考 本章为选择题题库,试…...
OpenCV笔记:图像去噪对比
图像去噪对比 1. 均值滤波(Mean Filtering) 方法:用像素周围的像素平均值替换每个像素值。适用场景:适用于去除随机噪声,如在不强调图像细节的场景中,如果图像细节较多时,可能会导致图像模糊。…...
A-B数对(二分查找)
#include<bits/stdc.h> using namespace std;using ll long long;int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n,c;cin>>n>>c;int nu[200000];for(int i0;i<n;i){cin>>nu[i]; // 输入数组元素}sort(nu,nun);ll cnt0; // 统计满…...
Vue 的各个生命周期
详解 Vue 的各个生命周期 文章目录 详解 Vue 的各个生命周期Vue 组件的生命周期1.1 创建阶段示例: 1.2 挂载阶段示例: 1.3 更新阶段示例: 1.4 销毁阶段示例: 生命周期总结生命周期钩子对比表参考链接 Vue 组件的生命周期 在 Vue …...
实现简易计算器 网格布局 QT环境 纯代码C++实现
问题:通过代码完成一个10以内加减法计算器。不需要自适应,界面固定360*350。 ""按钮90*140,其它按钮90*70。 参考样式 #define DEFULT_BUTTON_STYLE "\ QPushButton{\color:#000000;\border:1px solid #AAAAAA;\border-radi…...
后端开发详细学习框架与路线
🚀 作者 :“码上有前” 🚀 文章简介 :后端开发 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 为帮助你合理安排时间,以下是结合上述学习内容的阶段划分与时间分配建议。时间安排灵活&a…...
2.langchain中的prompt模板 (FewShotPromptTemplate)
本教程将介绍如何使用 LangChain 库中的 PromptTemplate 和 FewShotPromptTemplate 来构建和运行提示(prompt),并通过示例数据展示其应用。 安装依赖 首先,确保你已经安装了 langchain 和相关依赖: pip install lan…...
FairGuard游戏加固实机演示
此前,FairGuard对市面上部分游戏遭遇破解的案例进行了详细分析,破解者会采用静态分析与动态调试相结合的手段,逆向分析出代码逻辑并对其进行篡改,实现作弊功能,甚至是对游戏资源文件进行篡改,从而制售外挂。…...
Spark使用过程中的 15 个常见问题、详细解决方案
目录 问题 1:Spark 作业超时问题描述解决方案Python 实现 问题 2:内存溢出问题描述解决方案Python 实现 问题 3:Shuffle 性能问题问题描述解决方案Python 实现 问题 4:Spark 作业调度不均问题描述解决方案Python 实现 问题 5&…...
算法【最长递增子序列问题与扩展】
本文讲解最长递增子序列以及最长不下降子序列的最优解,以及一些扩展题目。本文中讲述的是最优解,时间复杂度是O(n*logn),空间复杂度O(n),好实现、理解难度不大。这个问题也可以用线段树来求解,时间和空间复杂度和本节讲…...
k8s篇之flannel网络模型详解
在 Kubernetes (K8s) 中,Flannel 是一种常用的网络插件,用于实现容器之间的网络通信。Flannel 提供了一种覆盖网络(Overlay Network)模型,使得容器可以跨多个主机进行通信。 以下是 Flannel 在 Kubernetes 中的详细工作原理和覆盖网络模型的详解: 1.Flannel 简介 Flann…...
windows 和 linux检查操作系统基本信息
windows检查操作系统基本信息 systeminfolinux检查操作系统基本信息 获取系统位数 getconf LONG_BIT查询操作系统release信息 lsb_release -a查询系统信息 cat /etc/issue查询系统名称 uname -a...
Oracle OCP认证考试考点详解082系列22
题记: 本系列主要讲解Oracle OCP认证考试考点(题目),适用于19C/21C,跟着学OCP考试必过。 105. 第105题: 题目 解析及答案: 题目翻译: 关于Oracle数据库中的事务请选择两个正确的陈述…...
线性回归 - 最小二乘法
线性回归 一 简单的线性回归应用 webrtc中的音视频同步。Sender Report数据包 NTP Timestamp(网络时间协议时间戳):这是一个64位的时间戳,记录着发送SR的NTP时间戳,用于同步不同源之间的时间。RTP Timestamp࿱…...
Linux - 线程基础
文章目录 1.什么是线程2.线程vs进程3.线程调度4.线程控制4.1 POSIX线程库4.2创建线程4.3线程终止4.4线程等待4.5线程分离 5、线程封装 1.什么是线程 在Linux操作系统中,线程是进程内部的一个执行流。在Linux操作系统下,执行流统称为轻量级进程࿰…...
17网站一起做网店 每日新款/百度seo关键词排名优化教程
linux 安装ibus,中文输入法 IBUS输入法安装和设置 IBus是一个框架,支持多种输入法。 问题1:Ubuntu系统选择自带的拼音输入法是错误的,它默认无法输入中文及中文词组,请独立安装其他基于IBus的输入法 问题2࿱…...
小程序开发北京华网天下首选/合肥seo管理
是否被整除 时间限制:1000 ms | 内存限制:65535 KB难度:2描述一个位数不大于100万位的正整数,如果它既能被11整除又能被2的n次方整除就输出YES否则输出NO 输入输入有多组数据每组数据有两行第一行一个n代表2的n次方(…...
深圳市专注网站建设/搜索推广
智器Ten3从一上市就采用了最新的Android4.0系统,随着时间的推移官方已经更新至了最新的Android4.0.3版本。在上一页笔者已经简要的介绍了一下系统升级的步骤,可以看出智器平板的升级操作还是非常简单的。Ten3采用最新的Android4.0.3系统谷歌最新的Androi…...
浙江网站建设价格/中国万网域名注册服务内容
在Maven中依赖的域有: compile、provided、runtime、system、test、import。 依赖范围(Scope)编译classpath测试classpath运行时classpath传递性说明compileYYYYspring-coretest-Y--junitprovidedYY--servlet-apiruntime-YYYjdbc驱动systemYY--本地jar包compile&am…...
上海高端网站制作站霸科技/360搜索建站
请问下面的matlab代码每一项具体代表什么意思?关注:104 答案:2 手机版解决时间 2021-01-25 11:33已解决2021-01-25 07:10lineshoughlines(BW,T,R,P,FillGap,50,MinLength,7)最佳答案2021-01-25 08:37首先讲一下这个函数:houghlines这个函数在matlab中有…...
做网站公司(信科网络)/今日大事件新闻
原论文:Erica Rutter, John Lagergren, Kevin Flores. Automated Object Tracing for Biomedical Image Segmentation Using a Deep Convolutional Neural Network. MICCAI 2018.简介卷积神经网络近年来在许多生物医学图像任务中取得了领先的成果。CNN已经被广泛用于…...