使用 flask-login 扩展
实现授权系统的一种更简单的方法是使用 flask-login 扩展。该项目的网站包含一个详细而精心编写的快速入门,本例中提供了较短版本。
大概的概念
该扩展公开了一组用于以下的函数:
- 记录用户
- 记录用户
- 检查用户是否登录,并找出哪个用户
什么不做,你自己要做什么:
- 没有提供存储用户的方法,例如在数据库中
- 没有提供检查用户凭据的方法,例如用户名和密码
下面是一整套工作所需的最小步骤。
我建议将所有与 auth 相关的代码放在单独的模块或包中,例如 auth.py
。这样,你可以单独创建必要的类,对象或自定义函数
创建一个 LoginManager
扩展使用 LoginManager
类,必须在 Flask
应用程序对象上注册。
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app) # app is a Flask object
如前所述,LoginManager
例如可以是单独文件或包中的全局变量。然后可以将其导入到创建 Flask
对象的文件中或在应用程序工厂函数中进行初始化。
指定用于加载用户的回调
通常会从数据库加载用户。回调必须返回一个对象,该对象表示与提供的 ID 相对应的用户。如果 ID 无效,则应返回 None
。
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id) # Fetch the user from the database
这可以在创建你的 LoginManager
之后直接完成。
代表你的用户的类
如上所述,user_loader
回调必须返回代表用户的对象。这究竟是什么意思?例如,该对象可以是存储在数据库中的用户对象的包装器,也可以是数据库中直接的模型。该对象必须实现以下方法和属性。这意味着如果回调返回数据库模型,则需要确保将所提及的属性和方法添加到模型中。
-
is_authenticated
如果用户已通过身份验证,则此属性应返回
True
,即他们已提供有效凭据。你需要确保user_loader
回调返回的代表你的用户的对象返回该方法的True
。 -
is_active
如果这是一个活跃用户,则此属性应返回 True - 除了经过身份验证之外,他们还激活了帐户,未被暂停,或者你的应用程序拒绝帐户的任何条件。非活动帐户可能无法登录。如果你没有此类机制,请从此方法返回
True
。 -
is_anonymous
如果这是匿名用户,则此属性应返回 True。这意味着
user_loader
回调返回的用户对象应返回True
。 -
get_id()
此方法必须返回唯一标识此用户的 unicode,并且可用于从
user_loader
回调加载用户。请注意,这必须是 unicode - 如果 ID 本身是 int 或其他类型,则需要将其转换为 unicode。如果user_loader
回调从数据库返回对象,则此方法很可能返回此特定用户的数据库 ID。相同的 ID 当然应该导致user_loader
回调稍后返回同一个用户。
如果你想使事情变得更容易为自己(**它实际上是推荐),你可以继承 UserMixin
由 user_loader
回调(大概数据库模型)返回的对象。你可以在此处查看默认情况下如何实现这些方法和属性。
记录用户
该扩展程序将验证用户输入的用户名和密码。事实上,如果你使用用户名和密码组合或其他机制,扩展程序并不在意。这是使用用户名和密码记录用户的示例。
@app.route('/login', methods=['GET', 'POST'])
def login():
# Here we use a class of some kind to represent and validate our
# client-side form data. For example, WTForms is a library that will
# handle this for us, and we use a custom LoginForm to validate.
form = LoginForm()
if form.validate_on_submit():
# Login and validate the user.
# user should be an instance of your `User` class
login_user(user)
flask.flash('Logged in successfully.')
next = flask.request.args.get('next')
# is_safe_url should check if the url is safe for redirects.
# See http://flask.pocoo.org/snippets/62/ for an example.
if not is_safe_url(next):
return flask.abort(400)
return flask.redirect(next or flask.url_for('index'))
return flask.render_template('login.html', form=form)
通常,日志记录用户是通过调用 login_user 并将表示前面提到的用户的对象实例传递给它来完成的。如图所示,这通常发生在从数据库中检索用户并验证其凭据之后,但是在此示例中,用户对象只是神奇地出现。
我已登录用户,现在怎么办?
user_loader
回调返回的对象可以通过多种方式访问。
-
在模板中:
扩展使用模板上下文处理器以名称
current_user
自动注入它。要禁用该行为,请在LoginManager
构造函数中使用自定义处理器集add_context_processor=False
。{% if current_user.is_authenticated %} Hi {{ current_user.name }}! {% endif %}
-
在 Python 代码中:
扩展提供了一个名为
current_user
的请求绑定对象。from flask_login import current_user @app.route("/hello") def hello(): # Assuming that there is a name property on your user object # returned by the callback if current_user.is_authenticated: return 'Hello %s!' % current_user.name else: return 'You are not logged in!'
-
使用装饰器快速限制访问
login_required
装饰器可用于快速限制访问。from flask_login import login_required @app.route("/settings") @login_required def settings(): pass
记录用户
用户可以通过调用 logout_user()
注销 。即使用户没有登录也似乎是安全的,因此 @login_required
装饰器很可能被省略。
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(somewhere)
如果用户未登录并访问 current_user
对象会发生什么?
通过 defult 返回 AnonymousUserMixin :
is_active
和is_authenticated
是False
is_anonymous
是True
get_id()
返回None
要为匿名用户使用不同的对象,请提供一个可调用的(类或工厂函数),为你的 LoginManager
创建匿名用户:
login_manager.anonymous_user = MyAnonymousUser
接下来是什么?
以上是对扩展的基本介绍。要了解有关配置和其他选项的更多信息,强烈建议你阅读官方指南 。