Flask - Login

文档:https://flask-login.readthedocs.io/en/latest/
中文文档1:http://docs.jinkan.org/docs/flask-login/
中文文档2:http://www.pythondoc.com/flask-login/
本文源码:https://github.com/SingleDiego/flask-login




安装

$ pip install flask-login




在应用中配置

初始配置方法:

from flask_login import LoginManager

login_manager = LoginManager()
login_manager.init_app(app)

然后我们需要定义一个 user_loader 回调,用来通过 唯一的 id 获取特定用户对象。例如这样:

# 这段代码通常放在定义 User 的 models 文件中
from app import login_manager

@login_manager.user_loader
def load_user(userid):
    # 这个方法由你使用的数据库来决定
    return User.get(userid)

如果 ID 无效,它应该返回 None ( 而不是抛出异常 )。




用户类

我们的用户模型除了用户名和密码等字段以外,还需要实现以下字段和方法:

  • is_authenticated
    当用户通过验证时,也即提供有效证明时返回 True 。(只有通过验证的用户会满足 login_required 的条件。)

  • is_active
    如果这是一个活动用户且通过验证,账户也已激活,未被停用,也不符合任何你 的应用拒绝一个账号的条件,返回 True 。不活动的账号可能不会登入(当然, 是在没被强制的情况下)。

  • is_anonymous
    如果是一个匿名用户,返回 True 。(真实用户应返回 False 。)

  • get_id()
    返回一个能唯一识别用户的,并能用于从 user_loader 回调中加载用户的 unicode 。注意着 必须 是一个 unicode —— 如果 ID 原本是 一个 int 或其它类型,你需要把它转换为 unicode 。

当然我们可以不去自己编写这些字段,因为 Flask-Login 在 UserMixin 类中提供了他们, 我们只需要把用户模型继承它,它提供了对所有这些方法的默认实现。

from flask_login import UserMixin

class User(UserMixin, db.Model):
    ……

出于安全的考虑我们不应该储存用户的明文密码,我们使用 Werkzeug 包的方法来给密码进行哈希加密。

from flask_login import UserMixin
from werkzeug.security import (
    generate_password_hash, 
    check_password_hash
    )

class User(UserMixin, 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 __repr__(self):
        return '<User {}>'.format(self.username)

    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)




用户登录

用户通过验证后,用 login_user 函数来登入他们。下面是一个验证登陆的例子:

from flask_login import login_user,

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        username = form.data.get('username', None)
        password = form.data.get('password', None)

        user = User.query.filter(username==username).first()
        # 验证用户名和秘密,如正确执行登陆操作
        if user and user.check_password(password):
            flash(u'欢迎你:{}!'.format(user.username))
            login_user(user)
        else:
            flash(u'用户名或密码错误!')

        return redirect(url_for('index'))

    return render_template('login.html', title='Sign In', form=form)

使用 current_user 可以获取到登录的用户,如果用户未登录则会返回一个 flask_login.mixins.AnonymousUserMixin 实例。

在视图函数中直接引入后使用:

from flask_login import current_user

在模板中可直接使用:

{% if current_user.is_authenticated %}
    <a>当前用户:{{ current_user.username }}</a>
{% else %}
    <a>未登录</a>
{% endif %}




登录检查

需要用户登入才能访问的视图可以用 @login_required 装饰器来装饰。

from flask_login import login_required

@app.route("/settings")
@login_required
def settings():
    pass

未登录的情况下访问该视图 Flask-Login 会重定向到登录视图并闪现(Flash)一条消息。如果未设置登录视图,它将会以 401 错误退出。

登录视图在 login_manager.login_view 设置,例如:

login_manager.login_view = "login"

其参数等同于 url_for 中的参数。

默认的闪现消息是 “Please log in to access this page.”。要自定义该信息,请设置 LoginManager.login_message

login_manager.login_message = u"请先登录以浏览该页面。"

要自定义消息分类的话(消息分类详情见:消息闪现 一章),请设置 LoginManager.login_message_category

login_manager.login_message_category = "info"

当重定向到登入视图,它的请求字符串中会有一个 next 变量,其值为用户之前访问的页面。我们可以这样获取他:

next = request.args.get('next')

利用这个变量我们可以实现登陆后跳转到登陆前所在页面的功能:

from werkzeug.urls import url_parse

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        username = form.data.get('username', None)
        password = form.data.get('password', None)
        remember_me = form.data.get('remember_me')

        user = User.query.filter_by(username=username).first()

        if user and user.check_password(password):
            flash(u'欢迎你:{}!'.format(user.username))
            login_user(user)
            # 登录后跳转到登陆前所在页面
            next = request.args.get('next')
            # 如果 next 为空或包含域名,判断为不合法的参数
            if next == None or url_parse(next).netloc != '':
                return redirect(url_for('index'))
            else:
                return redirect(next)
        else:
            flash(u'用户名或密码错误!')

        return redirect(url_for('index'))
    return render_template('login.html', title='Sign In', form=form)

对于 next 参数,我们必须进行校验以防跳转到其他恶意网址。正常情况下,next 参数应该是一个相对路径(如:/test),攻击者可能会在 next 参数中附上包含域名的完整 URL 来达到跳转到恶意链接的目的。我们应当校验这种情况。




用户登出

通过 Flask-Login 的 logout_user() 函数来实现登出功能

from flask_login import logout_user

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 最近在学习flask,用到flask-login,发现网上只有0.1版本的中文文档,看了官方已经0.4了,并且添加...
    ZZES_ZCDC阅读 5,934评论 3 24
  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,159评论 22 257
  • 配置应用对一个使用 Flask-Login 的应用最重要的一部分就是 LoginManager 类。你应该在你的代...
    icecrea阅读 555评论 0 2
  • 关于Flask登录认证的详细过程请参见拙作<<使用Flask实现用户登陆认证的详细过程>>一文,而本文则偏重于详细...
    geekpy阅读 28,656评论 5 28
  • Flask-Login为Flask提供了用户会话管理。它处理了日常的登入,登出并且长时间记住用户会话; 用户登陆程...
    猴子精h阅读 343评论 0 0