使用passlib验证特殊字符密码失败及跨语言base64编码解决
问题描述
我在使用passlib==1.7.1处理密码哈希与验证时遇到了特殊字符兼容问题:
- 导入方式:
from passlib.apps import custom_app_context as pwd_context - 哈希密码:
pwd_context.encrypt(password) - 验证密码:
pwd_context.verify(password, self.password_hash)
不含特殊字符的常规密码验证完全正常,但只要密码包含£或$这类特殊字符,验证就会失败。
排查过程
一开始我以为是passlib的哈希逻辑出了问题,反复测试本地哈希与验证流程都没发现异常,后来才定位到Angular4向Flask应用发送Base64授权头的环节。
我之前使用的编码代码如下:
let headers: Headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'Basic ' + btoa(userLoginRequest.username + ':' + userLoginRequest.password) });
测试后发现,JavaScript的btoa()函数仅支持ASCII字符,对Unicode特殊字符的处理和Python的Base64编码逻辑存在差异,导致Python端解码这些特殊字符时出现乱码,最终引发密码验证失败。
解决方法
问题已经完美解决!我实现了一个专门适配Unicode字符串的Base64编码函数,代码如下:
b64EncodeUnicode(str) : string{ return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) { return String.fromCharCode(parseInt(p1, 16)) })) }
将原来直接调用btoa()的地方替换成这个函数后,含特殊字符的密码验证就完全正常了。
内容的提问来源于stack exchange,提问作者Doug




