告别jsencrypt!在若依管理系统中快速切换为SM2国密加密登录
若依管理系统国密SM2加密登录实战:从RSA平滑迁移到SM2的最佳实践
在数字化转型浪潮中,企业级应用系统的数据安全防护等级要求越来越高。作为国内广泛使用的开源后台管理系统,若依(RuoYi)默认采用RSA算法实现登录密码加密传输,而随着《密码法》的颁布实施和国家对商用密码应用的推广,SM2国密算法正逐步成为企业合规建设的标配。本文将手把手带你完成若依系统中从RSA到SM2加密方案的平滑升级,涵盖密钥管理、前后端改造和兼容性处理等核心环节。
1. 国密算法选型与准备工作
1.1 为什么选择SM2替代RSA?
SM2作为国家密码管理局发布的椭圆曲线公钥密码算法,相比RSA具有三大显著优势:
- 安全性更高:256位SM2密钥强度相当于3072位RSA,且抗量子计算攻击能力更强
- 运算效率更优:相同安全强度下,SM2签名速度比RSA快10倍以上
- 合规性要求:满足等保2.0和行业监管对商用密码应用的要求
技术参数对比:
| 指标 | SM2 | RSA-2048 |
|---|---|---|
| 密钥长度 | 256位 | 2048位 |
| 签名速度 | 10,000次/秒 | 1,200次/秒 |
| 加密速度 | 8,500次/秒 | 900次/秒 |
| 国家标准 | GM/T 0003-2012 | PKCS#1 |
1.2 开发环境准备
开始改造前需要确认以下环境就绪:
基础环境:
- JDK 1.8+(推荐Amazon Corretto 11)
- Maven 3.6+
- Node.js 14+
依赖库:
- 后端:
sm-cryptoJava版(0.3.2+) - 前端:
sm-cryptoJavaScript版(1.0+)
- 后端:
密钥工具:
- OpenSSL 1.1.1+(支持SM2算法)
- 国密SSL测试工具
提示:建议在测试环境先完成验证,再应用到生产系统。密钥对生成务必在安全隔离环境中进行。
2. 后端核心改造实战
2.1 SM2密钥对生成与管理
与RSA不同,SM2采用椭圆曲线密码体系,密钥生成方式有显著差异。我们通过Java代码实现密钥对生成:
// SM2密钥工具类核心方法 public static String[] generateKeyPair() throws Exception { Keypair keypair = Sm2.generateKeyPairHex(); String[] result = new String[2]; if (keypair != null) { result[0] = keypair.getPublicKey(); // 04开头的非压缩公钥 result[1] = keypair.getPrivateKey(); // 64字符十六进制私钥 } return result; }生成的密钥需要安全存储:
- 公钥:可前端硬编码或通过接口动态获取
- 私钥:
- 生产环境建议使用HSM或KMS管理
- 测试环境可存储在配置文件中:
# application.yml sm2: private-key: "92b704fee9ac448ac27abfa537021ab42d0035151f01fdc03e49b0c2f5496148"
2.2 加解密服务改造
创建SM2Encryptor工具类封装核心操作:
public class SM2Encryptor { private static final String PRIVATE_KEY = "${sm2.private-key}"; // 加密方法 public static String encrypt(String plainText, String publicKey) { return Sm2.doEncrypt(plainText, publicKey, 1); // 1表示C1C3C2模式 } // 解密方法 public static String decrypt(String cipherText) { return Sm2.doDecrypt(cipherText, PRIVATE_KEY, 1); } }登录接口改造要点:
@PostMapping("/login") public AjaxResult login(@RequestBody LoginBody loginBody) { // 解密SM2加密的密码 String password = SM2Encryptor.decrypt(loginBody.getPassword()); // 后续认证逻辑不变 String token = loginService.login(loginBody.getUsername(), password, ...); return AjaxResult.success().put(Constants.TOKEN, token); }3. 前端改造与兼容方案
3.1 加密模块集成
安装SM2加密库:
npm install sm-crypto --save创建加密工具文件src/utils/smCrypto.js:
import { sm2 } from 'sm-crypto' const publicKey = '04b9fd451e0d0d5517069076edbc7dc83b3a885307bc8cf00185769f6818bcdf958f8dc4c8575f33dcfbe0bb18c4f651892a05a4fd923f01db2e3ad09fc4bf2878' const cipherMode = 1 // 推荐C1C3C2模式 export const encryptPassword = (pwd) => { return sm2.doEncrypt(pwd, publicKey, cipherMode) }3.2 登录表单改造
在登录提交时调用加密方法:
import { encryptPassword } from '@/utils/smCrypto' function handleLogin() { loginForm.value.password = encryptPassword(loginForm.value.password) // 后续登录逻辑不变 }4. 平滑迁移与异常处理
4.1 双算法兼容方案
为保障过渡期用户体验,建议实现双算法兼容:
// 解密工具类增加自动识别 public static String decryptPassword(String cipherText) { try { // 先尝试SM2解密 return SM2Encryptor.decrypt(cipherText); } catch (Exception e1) { try { // SM2失败尝试RSA解密 return RSAEncryptor.decrypt(cipherText); } catch (Exception e2) { throw new ServiceException("解密失败"); } } }4.2 常见问题排查
加密失败:
- 检查公钥格式(应以04开头)
- 确认明文非空且为字符串类型
解密异常:
try { return Sm2.doDecrypt(cipherText, privateKey, 1); } catch (Exception e) { log.error("SM2解密失败:{}", e.getMessage()); // 可在此添加告警通知 throw e; }性能优化:
- 使用
Sm2Pool实现对象池化 - 考虑启用缓存减少密钥解析开销
- 使用
实际项目中,我们在金融系统迁移时发现IE11兼容性问题,最终通过引入sm2.js的polyfill解决。建议在测试阶段覆盖所有目标浏览器版本。
