美文网首页
Flask - Login

Flask - Login

作者: SingleDiego | 来源:发表于2018-09-24 11:06 被阅读111次

    文档: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'))
    

    相关文章

      网友评论

          本文标题:Flask - Login

          本文链接:https://www.haomeiwen.com/subject/bihanftx.html