前言
开发中必经的用户登录模块中,通常为了用户的隐私安全,存在数据库中的密码都是经过加密的,这也是常识。密码存储无非就是分为两种,明文存储(裸奔😐)与加密存储,而加密存储就是通过一定的对原始密码进行变换,从而使密码原文不容易被识别。
而密码加密通常有如下算法:
- 明文转码加密算法:BASE64 , 7BIT 等,严格来说这种方式不算真正的加密,只不过“看上去”加密了而已;
- 对称加密算法:DES、RSA 等;
- 签名加密算法:也可以理解为单向哈希加密,比如 MD5、SHA1 等。加密算法固定,容易被暴力破解,如果密码相同,得到的哈希值是一样的;
- 加盐哈希加密算法:加密是混入一段随机字符串(盐值)再进行哈希加密;正因为每次都是随机加入,也就是说,即使密码相同,如果盐值不同,哈希值也是不同的。现在网站开发主要都是用这种加密算法。
Flask 中的密码加密和解密(验证)
一般会使用 flask 中的 generate_password_hash()
和 check_password_hash()
进行加密和解密,使用之前先从 werkzeug 库中导入:
from werkzeug.security import generate_password_hash, check_password_hash
generate_password_hash()
其中这个函数最重要的就是里面的三个参数,generate_password_hash(password, method="pbkdf2:sha256", salt_length=16)
:
password
:即你要加密的明文密码;method
:哈希的方式(需要是 hashlib 库支持的),默认为 SHA256 ,格式为:pbpdf2:<method>[:iterations]
;iterations
:(可选参数)表示迭代次数,默认为 1000;
salt_length
:盐值的长度,默认为 16;(也就是随机加入字符串的长度,有些版本盐值长度为 8)。
一般如果不改变加密方式或者盐值长度可直接调用函数传入第一个参数即可,即传入你要加密的明文密码;一般加密强度选择默认已经足够了,如果想要更加强的加密,则改变盐值长度和迭代次数即可,最后生成的 hash 值格式如下:
method$salt$hash
check_password_hash
与 generate_password_hash()
所对应的,在写验证密码是否一致的逻辑时可用到,check_password_hash(pwhash, password)
两个参数:
pwhash
:上面使用generate_password_hash()
所生成的字符串;password
:需要验证的明文密码。
需要注意:check_password_hash()
返回的是布尔值。
实例
一般这两个函数会同时使用,用来检测用户输入的登录密码与数据库是否一致;下面给出视图函数中的一个实例,模板文件就不给出了,就是从表单中获取到用户的用户名、密码;
# 注册
@user_bp1.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
repassword = request.form.get('repassword')
phone = request.form.get('phone')
email = request.form.get('email')
if password == repassword:
# 注册用户
user = User()
user.username = username
# 使用自带的函数实现加密
user.password = generate_password_hash(password)
user.phone = phone
user.email = email
# 添加并提交
db.session.add(user)
db.session.commit()
return redirect(url_for('user.index'))
return render_template('user/register.html')
# 用户登录
@user_bp1.route('/login', methods=['GET','POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
users = User.query.filter(User.username == username).all()
for user in users:
# 如果 flag 为 true 表示匹配,否则密码不匹配;
flag = check_password_hash(user.password, password)
if flag:
return '用户登录成功!'
else:
return render_template('user/login.html', msg='用户名或者密码有误')
return render_template('user/login.html')
有些细节没有完善,只需要关注这两个函数的用处;User
是所定义的用户模型,这里还是要提醒一下:由于加密后的字段长度会很大,所以一开始设置模型的时候就应该把字段值设置的大一点,这里我设置了:password = db.Column(db.String(150),nullable=False)
,经过验证是足够使用的。
另外也附上这两个函数的简单调用实例:
from werkzeug.security import generate_password_hash, check_password_hash
# 明文密码
password = 'this_is_a_password'
# 生成加密哈希值
password_hash = generate_password_hash(password)
print(password_hash)
# 验证密码(正确)
is_true = check_password_hash(password_hash, password)
print(is_true)
# 验证密码(错误)
is_true1 = check_password_hash(password_hash, "there_are_many_passwords")
print(is_true1)
结果如下: