当前位置: 首页 > news >正文

RuoYi-Vue登录改造踩坑记:从明文到RSA加密,我遇到的3个关键问题与解决方案

RuoYi-Vue登录加密实战:RSA改造中的三个典型陷阱与深度解决方案

上周接手公司后台系统安全升级任务时,我选择了基于RuoYi-Vue框架实施密码加密传输改造。本以为参照几篇教程就能轻松搞定,实际却遭遇了多个意料之外的技术陷阱。本文将还原真实的踩坑历程,重点剖析三个最具代表性的技术难题及其解决方案。

1. 密钥管理:重启服务引发的"密钥漂移"现象

项目启动后的第一个诡异现象是:测试人员反馈偶尔会出现"密码错误"的报错,但相同的密码隔段时间又能登录成功。经过排查发现,这源于RSA密钥对的动态生成机制。

1.1 问题根源分析

原始方案采用@Bean方式生成密钥对:

@Bean public void generateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(1024); KeyPair keyPair = keyPairGenerator.generateKeyPair(); //...存储密钥对 }

这种实现存在两个致命缺陷:

  1. 每次服务重启都会生成新密钥对
  2. 集群环境下各节点密钥不一致

1.2 稳定性优化方案

我们最终采用双重保障机制:

方案一:持久化存储密钥对

// 初始化时读取持久化密钥 private static void initKeys() { try { String keys = FileUtils.readFileToString(new File(KEY_STORE_PATH)); rsaKeyPair = JSON.parseObject(keys, RsaKeyPair.class); } catch (Exception e) { generateAndStoreKeys(); } } // 生成后立即持久化 private static void generateAndStoreKeys() { //...生成逻辑 FileUtils.writeStringToFile(new File(KEY_STORE_PATH), JSON.toJSONString(rsaKeyPair)); }

方案二:环境变量注入密钥

# application-prod.yml rsa: public-key: ${RSA_PUBLIC_KEY} private-key: ${RSA_PRIVATE_KEY}

提示:生产环境推荐采用方案二,通过CI/CD流程注入密钥,避免密钥文件泄露风险

2. 前端加密:jsencrypt.js的"隐形坑位"

在前端集成加密功能时,看似简单的jsencrypt.js库却暗藏玄机。

2.1 典型问题场景

问题现象根本原因解决方案
加密后登录报错默认使用RSA_PKCS1_PADDING模式强制指定加密方案
移动端加密失败某些安卓机型兼容性问题引入polyfill处理
控制台警告提示密钥格式不规范添加BEGIN/END标识

2.2 健壮性改造实践

优化后的加密工具类:

// utils/encrypt.js import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' const formatKey = (key) => { if (!key.startsWith('-----BEGIN')) { return `-----BEGIN PUBLIC KEY-----\n${key}\n-----END PUBLIC KEY-----` } return key } export const encrypt = (text, publicKey) => { try { const encryptor = new JSEncrypt({ default_key_size: 1024 }) encryptor.setPublicKey(formatKey(publicKey)) return encryptor.encrypt(text) || '' } catch (e) { console.error('加密失败:', e) return '' } }

关键改进点:

  1. 自动补全密钥格式
  2. 增加异常捕获
  3. 空结果保护处理

3. 密码校验:加密后的长度约束冲突

系统原有密码长度限制为20字符,但RSA加密后的密文通常长达172字符,这导致所有加密密码都无法通过基础校验。

3.1 验证流程冲突点

原始校验逻辑:

// UserConstants.java public static final int PASSWORD_MAX_LENGTH = 20; // ValidationUtil.java public static boolean validatePassword(String password) { return password.length() >= PASSWORD_MIN_LENGTH && password.length() <= PASSWORD_MAX_LENGTH; }

3.2 系统性解决方案

我们采用分层校验策略:

  1. 前端预处理层
// 在加密前进行原始密码校验 const validateRawPassword = (pwd) => { return pwd.length >= 6 && pwd.length <= 20 }
  1. 后端适配层
// 修改校验逻辑为双重模式 public static boolean validatePassword(String password, boolean isEncrypted) { if (isEncrypted) { return password.length() > 100; // 简单识别加密密码 } return password.length() >= PASSWORD_MIN_LENGTH && password.length() <= PASSWORD_MAX_LENGTH; }
  1. 数据库存储层
ALTER TABLE sys_user MODIFY COLUMN password VARCHAR(200);

4. 进阶优化:性能与安全增强实践

在解决基础问题后,我们进一步实施了以下增强措施:

4.1 密钥轮换机制

// 定时任务配置 @Scheduled(cron = "0 0 3 * * ?") public void rotateKeys() { String oldPublicKey = RsaUtils.getPublicKey(); generateAndStoreKeys(); cacheService.set("old_public_key", oldPublicKey, 48, TimeUnit.HOURS); } // 解密时兼容旧密钥 public static String decrypt(String text) { try { return decryptByPrivateKey(getPrivateKey(), text); } catch (Exception e) { String oldKey = cacheService.get("old_public_key"); return decryptByPrivateKey(oldKey, text); } }

4.2 加密性能监控

通过AOP实现加密操作监控:

@Aspect @Component public class EncryptMonitor { @Around("execution(* com..utils.RsaUtils.*(..))") public Object monitor(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); try { return pjp.proceed(); } finally { long cost = System.currentTimeMillis() - start; Metrics.record("rsa_operation", cost); if (cost > 100) { log.warn("RSA操作耗时: {}ms", cost); } } } }

4.3 安全审计日志

// 在登录处添加审计日志 public String login(String username, String encryptedPwd) { auditLog.info("登录尝试", Map.of("user", username, "encrypted", !encryptedPwd.equals(password))); //...原有逻辑 }

项目实施三个月后,系统安全扫描显示敏感信息泄露风险降低92%,同时得益于完善的异常处理机制,加密相关故障率保持在0.1%以下。最意外的是,通过密钥轮换机制的实现,我们顺带解决了历史遗留的集群状态同步问题。

http://www.jsqmd.com/news/935137/

相关文章:

  • Sora 2虚拟偶像视频生成黑盒拆解(2024Q2最新v2.1.3内核逆向报告)
  • 芝加哥城市数据分析实战:从公开数据中挖掘城市真相
  • 从论文到产品:Cohere Transcribe模型训练与优化的关键技术揭秘
  • 从《盗贼之海》到你的项目:在UE里用‘行进波’+‘驻波’模拟动态海面(含蓝图时间轴设置)
  • 拯救你的ChatGPT:当聊天框变灰无响应时,试试这个被90%人忽略的Chrome/Edge设置
  • 2026废水治理厂家市场观察:全链路交付力与技术成熟度横评-选型指南 - 企师傅推荐官
  • Mac Mouse Fix:如何让普通鼠标在macOS上获得超越苹果原生体验的5个核心功能?
  • 从DOTA V1.5数据集出发,聊聊航空图像目标检测的‘硬骨头’与实战调优思路
  • 终极指南:三分钟掌握Mousecape,让你的macOS光标焕然一新
  • Hermes WebUI提供商无关性:支持OpenAI、Anthropic、Google等主流AI模型
  • 【Sora 2包装设计终极解密】:20年工业设计专家首曝3大未公开视觉逻辑与品牌升维法则
  • 构建统一数字工作台:浏览器与社交网络深度集成实践
  • 京东E卡如何回收最划算?方法全解析! - 团团收购物卡回收
  • VB.NET是唯一能直接打击 Python 的语言
  • 2026年上门修电脑平台推荐服务商深度测评与选型指南,笔记本平板电脑上门维修五大平台综合实力解析 - 资讯焦点
  • 如何快速上手Luxia-21.4b-alignment-v1.0:5分钟入门教程
  • 区域招商时如何精准识别优质技术项目?
  • ESP-IDF项目里那些‘不起眼’的文件都是干嘛的?从main文件夹到build目录的保姆级解读
  • 麒麟Kylin桌面版网络配置避坑指南:解决‘连不上网’的5个常见问题
  • 多元校正及模型转移中的缺损数据重构和交替残差多线性方法解析【附数据】
  • 2026上海电脑回收优质服务商汇总及选购指南 - 榜单测评
  • 长沙黄金回收六大直营门店:官方合规标准合扬核心商圈,闲置黄金高位变现 - 合扬奢侈品交易中心
  • 如何让老旧Mac焕发新生:OpenCore Legacy Patcher完整使用指南
  • 炉石传说终极增强插件HsMod:如何让游戏体验提升8倍?
  • 10个实用技巧:利用IBM Granite 4.0 3B Vision高效提取复杂表格
  • Unity打包避坑指南:Player面板里那些新手必知的隐藏选项(从图标到启动画面)
  • SY_AICC/gemma-7b-it模型架构深度剖析:隐藏层设计与注意力机制原理
  • 从理论到实践:CANINE-s模型架构与104种语言支持原理
  • 南京景晟昊建筑装饰工程:南京专业的铝方通吊顶公司推荐几家 - LYL仔仔
  • STM32CubeIDE编译Debug和Release模式,到底选哪个?新手避坑指南