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对象。它具有以下属性和方法:

  • is_active和是False
  • is_authenticatedFalse
  • is_anonymousTrue
  • get_id() :返回 None

如果对匿名用户有自定义要求(例如,他们需要具有权限字段),则可以提供一个可调用对象(类或工厂函数),该可调用对象通过以下方式创建匿名用户:

class AnonymousUser(AnonymousUserMixin):

    def can(self, permissions):
        return False

    def is_administrator(self):
        return False

login_manager.anonymous_user = AnonymousUser

参考

posted @ 2021-03-27 11:49  yangblood  阅读(2680)  评论(0编辑  收藏  举报