环境
Vue3、soybean admin: “1.0.0”(native-ui: “2.38.0”)、pnpm: “8.5.3”、jsencrypt: “3.3.2”
使用
后端那边要求使用RSA非对称性加密,查阅了网上的资料,CryptoJS并不支持RSA加密,所以选择JSEncrypt
1. 下载依赖
pnpm安装依赖JSEncrypt
pnmp install jsencrypt --save
2. 加密登录密码
后端会给出公钥,用于登录密码的加密,现在我们通过JSEncrypt进行RSA加密
加密密码的方法如下:
function getEncryptedPassword(value: string) { const publicKey = "" let encrypt = new JSEncrypt(); encrypt.setPublicKey(publicKey); let encrypted = encrypt.encrypt(value); return encrypted;}
3. 登录失败
输入密码:123456,点击登录,接口报错“用户名或密码不正确”。检查后发现,加密出来的字符串和API文档给的字符串不一样。
JSEncrypt加密
AiSCv0JWI47eEmwfCDdzH9jtHZZo/tREW3QO2JO54rNhHZ8YSOELUdWsMP4wfjKYxEZugXUujjK1xTUeejq/KWYbp9qlyInFA2xheNG4a3a+s6ER9NLrsT9LAvD6YP8JdF8EZDl/zCMlQ5Fdh6FqNKlOtIJuiGNhGoPe48y7N9I=
后端API文档示例
090558eddebdef1dd02fe0a8cd59524d5da249d19084333ab2cb050b66aca9f868145a090b643fd9087e7baf5c967c99104acafb4946e1ec5ed78e29957183e3e9955fd1b981728091435bde75da1f62f83202511a6dfbd625f9cf7942536422ad36f3e742804b6aa11aa27ce13ab4feb7b1d9ea7e2e8d3d876d9a685a2a18a9
一眼就不对劲,但是又不知道怎么能变成后端给出的那种编码。怀疑是JSEncrypt的问题。
尝试用后端给的私钥去解密:
function decryptPassword(encryptedPwd: string) { const privateKey= "" let decrypt = new JSEncrypt(); decrypt.setPublicKey(privateKey); let password = decrypt.decrypt(encryptedPwd); return password;}
解密出来确实也是123456,证明了RSA加密流程其实没有问题的,很神奇。
JSEncrypt文档给出的方法很少很少,不清楚如何转变成正确的编码。找了很多资料,最后发现了一个文章:Hutool配合jsencrypt进行RSA加解密,这个博主看了JSEncrypt源码,加密出来的字符串是Base64,而在解密的时候,会把传进来的Base64转成Hex,再去执行解密方法!
4. 解决问题
根据文章知道了,有种编码叫Hex,兴许后端给的就是Hex,直接用在线网站试了Base64转Hex,尝试了一下,果然就登录成功了!
重新整理加密代码,如下:
function getEncryptedPassword(value: string) { const publicKey = "" let encrypt = new JSEncrypt(); encrypt.setPublicKey(publicKey); let encrypted = encrypt.encrypt(value); // copy form stackoverflow let base64ToHex = (base64: string) => { var raw = atob(base64); var hex = ''; for (var i = 0; i < raw.length; i++) { var _hex = raw.charCodeAt(i).toString(16) hex += (_hex.length == 2 ? _hex : '0' + _hex); } return hex; } // JSEncrypt转成base64了,后端需要的是Hex const hexPassword = base64ToHex(encrypted.toString()); return hexPassword;}
5. 补充知识
对编码、加密解密不熟悉,导致一眼看不出问题,花了很多时间去排查。特别是一直以为Hex是哈希的意思,哈希跟加密也有点关联,一时间混淆了
科普一下
Hex,也就是十六进制,也称为Base16区分Base64:Base64使用一个包含64个字符的字符集,包括大写字母(A-Z)、小写字母(a-z)、数字(0-9)以及"+“和”/“符号。有时,Base64编码还会使用”="作为填充字符,以确保编码后的字符串长度是4的倍数。区分Base16:Base16(Hexadecimal)使用一个包含16个字符的字符集,包括数字(0-9)和字母(A-F)。Base16编码不使用"+“、”/“或”="字符。除了Base64、Base16,还有其它编码方式,比如Base32、Base58、ASCII编码、Unicode编码(UTF-8、UTF-16、UTF-32)、URL编码等等资料来自文心一言,欢迎评论指出问题!
总结
对于这次RSA非对称加密登录密码对接的问题,有两点总结:
之前加密密码都是用的CryptoJS,直接用盐加密登录就能成功,从来没有想过编码方式的问题还有其实网上使用RSA去加密登录密码的不多,用MD5、AES的比较多,这也是花了一些时间排查的原因。通过本次对接了解到了一些编码方面的知识,下次遇到应该不会那么懵了,希望能帮助到大家!