简单 flask_login 示例 - 这是正确的方法吗?
Simple flask_login example - is this the correct way?
下面我尝试创建一个非常简化和简单的 flask_login
实现。虽然它有效,但我只想确保我以正确的方式进行操作。特别是,我的密码验证方法是否正确?我的意思是正确的,我应该使用另一个 flask_login 函数来为我做这个检查吗?我这里有什么不需要的代码吗?
python 和 flask 还是新手,任何 advice/edits 都将不胜感激。
Username/password 检查:
if (username, password) in users_db.items():
login_user(User(username))
return redirect(request.args.get("next"))
else:
return abort(401)
else:
return Response('''
<form action="" method="post">
<p><input type=text name=username>
<p><input type=password name=password>
<p><input type=submit value=Login>
</form>
'''
整个 flask_login 尝试:
from flask import Flask, jsonify, render_template, request, url_for, redirect, session, abort, Response
from flask_login import LoginManager, UserMixin, login_required, login_user, logout_user
from flask_wtf import Form
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
#################### Instantiate APP ###################################
'''Application Factory'''
app = Flask(__name__)
app.config['SECRET_KEY'] = 'shhsecret' #make this more random and secret, i recommend using os.urandom(50)
#################### Authentication ####################################
# flask-login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
class LoginForm(Form):
username = StringField('Your username', validators=[DataRequired()])
password = PasswordField('Your password', validators=[DataRequired()])
submit = SubmitField('Sign In')
# silly user model
class User(UserMixin):
def __init__(self, username):
self.id = username
self.password = users_db[username]
def __repr__(self):
return "%s/%s" % ( self.id, self.password)
def is_active(self):
return True
#users database (used dictionary just as an example)
users_db = { 'bill':'password1'
,'jondoe': 'password2'
,'elonmusk' : 'passwordtesla'
}
# create users from our users database above
users_activated = {User(key) for (key,value) in users_db.items()}
# some protected url
@app.route('/protectedurl')
@login_required
def protectedurl_func():
return Response("Hello World!")
# somewhere to login
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if (username, password) in users_db.items():
login_user(User(username))
return redirect(request.args.get("next"))
else:
return abort(401)
else:
return Response('''
<form action="" method="post">
<p><input type=text name=username>
<p><input type=password name=password>
<p><input type=submit value=Login>
</form>
''')
# somewhere to logout
@app.route("/logout")
@login_required
def logout():
logout_user()
return Response('<p>Logged out</p>')
# handle login failed
@app.errorhandler(401)
def page_not_found(e):
return Response('<p>Login failed</p>')
# callback to reload the user object
@login_manager.user_loader
def load_user(userid):
return User(userid)
if __name__ == '__main__':
app.run(debug=True, use_reloader=True)
一切正常。但是,在处理用户数据时应考虑一些原则:
- 密码绝不能像用户给定的那样存储在数据库中
- 为了代码的可重用性,考虑关注点分离
Werkzeug 通常用于密码散列。当一个密码被“散列”后,这意味着它已经变成了它自己的一个加扰表示。
这是它在 python shell:
中的工作方式
>>> from werkzeug.security import generate_password_hash
>>> hash = generate_password_hash('my_password')
>>> hash
'pbkdf2:sha256:150000$aRIbsDylae44b1a5c679e08685c75ff0750df7c6670582a5839072d35a713316816760'
>>>
my_password
经过一系列没有已知逆向操作的密码运算变成了一个长编码字符串,这意味着获得哈希密码的人将无法使用它来获得原密码.
要验证用户密码,您可以这样做:
>>> from werkzeug.security import check_password_hash
>>> check_password_hash(hash, 'my_password')
True
>>> check_password_hash(hash, 'another_password')
False
>>>
此密码哈希是您应该存储在数据库中的内容:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
password_hash = db.Column(db.String(128))
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
您现在可以在路由中创建登录逻辑:
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user is None or not user.check_password(form.password.data):
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
return redirect(url_for('index'))
return render_template('login.html', title='Sign In', form=form)
验证检查主要是尝试查明用户是否已存在于数据库中。如果他们这样做,并且他们的用户名和密码正确,那么他们将登录。否则,他们将被重定向以尝试再次登录。
就关注点分离而言,您要做的是确保您的应用程序是使用模块构建的。我的意思是,有一个模块处理数据库问题,另一个模块处理视图,另一个错误等等。
下面我尝试创建一个非常简化和简单的 flask_login
实现。虽然它有效,但我只想确保我以正确的方式进行操作。特别是,我的密码验证方法是否正确?我的意思是正确的,我应该使用另一个 flask_login 函数来为我做这个检查吗?我这里有什么不需要的代码吗?
python 和 flask 还是新手,任何 advice/edits 都将不胜感激。
Username/password 检查:
if (username, password) in users_db.items():
login_user(User(username))
return redirect(request.args.get("next"))
else:
return abort(401)
else:
return Response('''
<form action="" method="post">
<p><input type=text name=username>
<p><input type=password name=password>
<p><input type=submit value=Login>
</form>
'''
整个 flask_login 尝试:
from flask import Flask, jsonify, render_template, request, url_for, redirect, session, abort, Response
from flask_login import LoginManager, UserMixin, login_required, login_user, logout_user
from flask_wtf import Form
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
#################### Instantiate APP ###################################
'''Application Factory'''
app = Flask(__name__)
app.config['SECRET_KEY'] = 'shhsecret' #make this more random and secret, i recommend using os.urandom(50)
#################### Authentication ####################################
# flask-login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
class LoginForm(Form):
username = StringField('Your username', validators=[DataRequired()])
password = PasswordField('Your password', validators=[DataRequired()])
submit = SubmitField('Sign In')
# silly user model
class User(UserMixin):
def __init__(self, username):
self.id = username
self.password = users_db[username]
def __repr__(self):
return "%s/%s" % ( self.id, self.password)
def is_active(self):
return True
#users database (used dictionary just as an example)
users_db = { 'bill':'password1'
,'jondoe': 'password2'
,'elonmusk' : 'passwordtesla'
}
# create users from our users database above
users_activated = {User(key) for (key,value) in users_db.items()}
# some protected url
@app.route('/protectedurl')
@login_required
def protectedurl_func():
return Response("Hello World!")
# somewhere to login
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if (username, password) in users_db.items():
login_user(User(username))
return redirect(request.args.get("next"))
else:
return abort(401)
else:
return Response('''
<form action="" method="post">
<p><input type=text name=username>
<p><input type=password name=password>
<p><input type=submit value=Login>
</form>
''')
# somewhere to logout
@app.route("/logout")
@login_required
def logout():
logout_user()
return Response('<p>Logged out</p>')
# handle login failed
@app.errorhandler(401)
def page_not_found(e):
return Response('<p>Login failed</p>')
# callback to reload the user object
@login_manager.user_loader
def load_user(userid):
return User(userid)
if __name__ == '__main__':
app.run(debug=True, use_reloader=True)
一切正常。但是,在处理用户数据时应考虑一些原则:
- 密码绝不能像用户给定的那样存储在数据库中
- 为了代码的可重用性,考虑关注点分离
Werkzeug 通常用于密码散列。当一个密码被“散列”后,这意味着它已经变成了它自己的一个加扰表示。
这是它在 python shell:
中的工作方式>>> from werkzeug.security import generate_password_hash
>>> hash = generate_password_hash('my_password')
>>> hash
'pbkdf2:sha256:150000$aRIbsDylae44b1a5c679e08685c75ff0750df7c6670582a5839072d35a713316816760'
>>>
my_password
经过一系列没有已知逆向操作的密码运算变成了一个长编码字符串,这意味着获得哈希密码的人将无法使用它来获得原密码.
要验证用户密码,您可以这样做:
>>> from werkzeug.security import check_password_hash
>>> check_password_hash(hash, 'my_password')
True
>>> check_password_hash(hash, 'another_password')
False
>>>
此密码哈希是您应该存储在数据库中的内容:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
password_hash = db.Column(db.String(128))
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
您现在可以在路由中创建登录逻辑:
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user is None or not user.check_password(form.password.data):
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
return redirect(url_for('index'))
return render_template('login.html', title='Sign In', form=form)
验证检查主要是尝试查明用户是否已存在于数据库中。如果他们这样做,并且他们的用户名和密码正确,那么他们将登录。否则,他们将被重定向以尝试再次登录。
就关注点分离而言,您要做的是确保您的应用程序是使用模块构建的。我的意思是,有一个模块处理数据库问题,另一个模块处理视图,另一个错误等等。