在做一个系统时,用户登录模块必不可少,当然用户名和密码就少不了了。在我接触flask框架之前,我都一直将密码直接保存进数据库的,大概就是这样👇哈哈哈哈哈啊哈哈哈哈很小新
最近在学习flask框架,今天看到可以通过Werkzeug外部库来实现密码的加密功能。将密码加密后再保存到数据库中,大概就是这样的👇
一、函数介绍
通过使用Werkzeug库中的security模块,可以很方便的实现密码散列值的计算功能。只需要如下两个函数即可实现这一功能,分别在注册用户和验证用户阶段。
-
generate_password_hash(password:str)
:功能是将原始密码作为输入,以字符串形式输出密码的散列值,输出的值可保存在用户数据库中。函数的参数其实还有method: str = "pbkdf2:sha256"
,salt_length: int = 16
,这个是默认参数不用多管。咱们实现就传入password
一个参数就够了。 -
check_password_hash(pwhash: str, password: str)
:功能是检查给出的hash密码与明文密码是否相符,参数pwhash
是从数据库中取回的密码散列值,password
是用户输入的密码。如果返回值为True,则表明密码正确;如果为False,则表明密码不正确。
二、功能实现
1.导包
这里导入的包只写了实现加密密码用到的包,如果您的项目中所需其他的包请读者自行添加。
from werkzeug.security import check_password_hash,generate_password_hash
2.User模型
定义实体类模型时,请记得要实现generate_password_hash()
和check_password_hash()
两个函数,实现很简单。
class User(db.Model):
__tablename__ = 'b_user'
id = db.Column(db.Integer, primary_key=True,autoincrement=True)
username = db.Column(db.String(30),unique=True)
password = db.Column(db.String(256))
def __init__(self, username, password):
self.username = username
self.password = password
def set_password(self,password):
self.password = generate_password_hash(password)
def check_password(self,password):
return check_password_hash(password)
3.用户注册
我写模型的时候,实例化对象需要传入username和password两个参数,实例化完成后,再用实例对象调用set_password()方法将对象的明文密码修改为hash密码,然后再将实例对象插入数据库。
@app.route('/regist',methods=['GET','POST'])
def regist():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username is None or password is None:
error = 'username or password is empty!'
return render_template('login.html',error=error)
else:
try:
user = User(username,password)
user.set_password(password)
db.session.add(user)
db.session.commit()
flash('Your regist successfully')
return redirect(url_for('login'))
except:
flash('error')
return redirect(url_for('login'))
else:
return render_template('regist.html')
5.用户登录
在这里踩了个小坑,就是最开始执行User.query.filter_by(username=username).first()
时,最开始我没有使用first()
函数,发现返回的值的类型并不是User实例对象,而是flask_sqlalchemy.BaseQuery
,值就是sql语句。所以在这去学习了filter()
和filter_by()
函数以及first()
和all()
函数。我在这篇blog看明白的,博主讲的很好。附上链接。
bloghttps://blog.csdn.net/weixin_45222544/article/details/103210684
代码里面的password1
是表单输入的明文密码,然后通过用户名查询实体类用户,通过user.password
获得注册时保存进数据库的hash密码。
@app.route('/login',methods=['GET','POST'])
def login():
error = None
print(get_flashed_messages())
if request.method == 'POST':
username = request.form.get('username')
password1 = request.form.get('password')
user = User.query.filter_by(username=username).first()
password_is_true = check_password_hash(user.password,password1)
if password_is_true == False:
return '您输入的用户名和或密码不正确'
else:
session['logged_in'] = True
flash('You were logged in')
return redirect(url_for('show_entries'))
else:
return render_template('login.html',error=error)
6.启动程序
if __name__ == '__main__':
app.run(debug=True)
请读者注意,本文所示代码并不全,无法直接运行,只是讲解密码加密的大致流程。如果您需要整个项目,我放在百度云了,请自行下载。另外大家如果有什么其他的见解或者我写博客有不足的地方,欢迎大家提出来!如果您觉得我写的还不错,点个赞支持一下,后面我会写更多东西出来与大家分享,谢谢
链接:https://pan.baidu.com/s/1bjI8GPbtOnDoO1-HLdiFlg
提取码:ny9j
2022.3.14更新
另外项目运行时,请先进行数据库迁移:
- python dbinit.py db init
- python dbinit.py db migrate
- python dbinit.py db upgrade