Flask:使用Flask-Login验证用户身份
Flask-Login提供Flask的用户会话(session)管理。它可以处理登录、注销、记住用户长时间会话 的常见任务。
Flask-Login可以:
- 将活动用户的ID存储在会话中,方便登录和注销用户
- 限制某些视图的访问(登录和未登录用户权限不同)
- 方便处理用户会话过期问题( “记住我” 的功能)
- 保护用户会话,防止cookie盗用
- 以后可与Flask-Principal或其他授权扩展相互集成使用
Flask-Login不可以:
- 不会增强数据库或其他存储的安全问题,只负责对登录用户的管理。
- 不限制用户身份验证方式,即:用户名密码,OpenID等认证方式。
- 不负责用户权限的处理,只负责用户登录登出。
- 不负责用户注册或账户找回。
1、安装配置
from flask_login import LoginManager
# ...
login_manager = LoginManager()
login_manager.init_app(app)
默认情况下,Flask登录使用session进行身份验证,需要配置SECRET_KEY。
1.1 配置模型
Flask-Login 的运转需要应用中有 User
对象。要想使用 Flask-Login 扩展,应用的 User
模型必须实现几个属性和方法:
属性/方法 | 说明 |
---|---|
is_authenticated |
如果用户提供的登录凭据有效,必须返回 True ,否则返回 False |
is_active |
如果允许用户登录,必须返回 True ,否则返回 False 。如果想禁用账户,可以返回 False |
is_anonymous |
对普通用户必须始终返回 False ,如果是表示匿名用户的特殊用户对象,应该返回 True |
get_id() |
必须返回用户的唯一标识符,使用 Unicode 编码字符串 |
这些属性和方法可以直接在模型类中实现,或使用Flask-Login 提供的 UserMixin
类,其中包含默认实现,能满足多数需求:
from flask_login import UserMixin
class User(UserMixin, db.Model):
# ...
1.2 配置 user_loader 回调
Flask-Login 要求应用指定一个函数,在扩展需要从数据库中获取指定标识符对应的用户时调用。login_manager.user_loader
装饰器把这个函数注册给 Flask-Login,在这个扩展需要获取已登录用户的信息时调用。传入的用户标识符是个字符串,因此这个函数先把标识符转换成整数,然后传给 Flask-SQLAlchemy 查询,加载用户。正常情况下,这个函数的返回值必须是用户对象;如果用户标识符无效,或者出现了其他错误,则返回 None
。
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
1.3 配置 login_view
默认情况下,当用户尝试访问视图需要登陆的视图时,如果未设置登录视图,它将中止并显示401错误。配置 login_view 后 Flask-Login将闪烁一条消息并将其重定向到登录视图。
# ...
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
2、登录示例
2.1 登入用户
在视图函数中,用户通过身份验证后,便可以使用该login_user
功能登录:
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
login_user(user)
flask.flash('Logged in successfully.')
next = flask.request.args.get('next')
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)
-
用户访问未授权的 URL 时会显示登录表单,Flask-Login 会把原 URL 保存在查询字符串的
next
参数中,这个参数可从request.args
字典中读取。如果查询字符串中没有next
参数,则重定向到首页。next
参数中的 URL 会经验证,确保是相对 URL,以防恶意用户利用这个参数,把不知情的用户重定向到其他网站。 -
login_user()
函数的参数是要登录的用户,以及可选的“记住我”布尔值,如果这个字段的值为False
,关闭浏览器后用户会话就过期了。如果值为True
,那么会在用户浏览器中写入一个长期有效的 cookie,使用这个 cookie 可以复现用户会话。cookie 默认记住一年,可以使用可选的REMEMBER_COOKIE_DURATION
配置选项更改这个值。# 配置项以 datetime.timedelta 对象或整数秒为单位。 class Config: # ... REMEMBER_COOKIE_DURATION = timedelta(hours=2)
2.2 访问用户
登入成功后,就可以在 视图函数 或 模板 中使用current_user
代理访问登录的用户对象:
{% if current_user.is_authenticated %}
Hi {{ current_user.name }}!
{% endif %}
2.3 限制视图
可以使用装饰login_required
器装饰需要用户登录的视图:
@app.route("/secrets")
@login_required
def secrets():
pass
2.4 用户登出
注销并将清除其会话中的所有cookie:
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(somewhere)
3、匿名用户
默认情况下,当用户未实际登录时,current_user
设置为AnonymousUserMixin
对象。它具有以下属性和方法:
如果对匿名用户有自定义要求(例如,他们需要具有权限字段),则可以提供一个可调用对象(类或工厂函数),该可调用对象通过以下方式创建匿名用户:
class AnonymousUser(AnonymousUserMixin):
def can(self, permissions):
return False
def is_administrator(self):
return False
login_manager.anonymous_user = AnonymousUser