二、Flask笔记-认证登录

• Flask-Login: 管理已登录用户的用户会话。
• Werkzeug: 计算密码散列值并进行核对。
• itsdangerous: 生成并核对加密安全令牌。

1. 创建认证蓝本:app/auth/__init__.py
from flask import Blueprint
auth = Blueprint('auth', __name__)
from . import views
2. 注册认证蓝本到create_app()工厂:app/__init__.py:
def create_app(config_name): 
    # ...
    from .auth import auth as auth_blueprint 
    app.register_blueprint(auth_blueprint, url_prefix='/auth')
    return app
3. 安装flask-login插件
pip install flask-login
4. 创建User模型保存用户登录信息:app/models.py
from flask_login import UserMixin
from . import db

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key = True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return '<User %r>' % self.username
5. 在User模型中实现密码散列:app/models.py
from werkzeug.security import generate_password_hash, check_password_hash
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
# ...

class User(UserMixin, db.Model):
    # ...
    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

说明:要保证数据库中用户密码的安全,关键在于不能存储密码本身,而要存储密码的散列 值。计算密码散列值的函数接收密码作为输入,使用一种或多种加密算法转换密码,最终 得到一个和原始密码没有关系的字符序列。核对密码时,密码散列值可代替原始密码,因 为计算散列值的函数是可复现的:只要输入一样,结果就一样。

6. 初始化Flask-Login:app/__init__.py
from flask_login import LoginManager

login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'

def create_app(config_name): 
    # ...
    login_manager.init_app(app)
    # ...

说明:LoginManager 对象的 session_protection 属性可以设为 None、'basic' 或 'strong',以提 供不同的安全等级防止用户会话遭篡改。设为 'strong' 时,Flask-Login 会记录客户端 IP 地址和浏览器的用户代理信息,如果发现异动就登出用户。login_view 属性设置登录页面 的端点。回忆一下,登录路由在蓝本中定义,因此要在前面加上蓝本的名字。

7. 设置用户回调函数:app/model.py
from . import login_manager

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

说明:Flask-Login 要求程序实现一个回调函数,使用指定的标识符加载用户。加载用户的回调函数接收以 Unicode 字符串形式表示的用户标识符。如果能找到用户,这 个函数必须返回用户对象;否则应该返回 None。

8. 通过Flask-Login提供的login_required装饰器来增加路由保护, 例如:
from flask_login import login_required

@app.route('/secret')
@login_required
def secret():
    return 'Only authenticated users are allowed!'

说明:如果未认证用户访问这个路由,Flask-Login会将这个请求发往登录页面。

9. 添加登录表单:app/auth/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo
from wtforms import ValidationError

class LoginForm(FlaskForm):
    email = StringField(u'邮箱', validators=[DataRequired(), Length(1, 64), Email()])
    password = PasswordField(u'密码', validators=[DataRequired()])
    remember_me = BooleanField(u'记住我')
    submit = SubmitField(u'登录')
10. 在视图中添加登录/登出功能:app/templates/base.html
<ul class="nav navbar-nav navbar-right">
    {% if current_user.is_authenticated() %}
        <li><a href="{{ url_for('auth.logout') }}">Sign Out</a></li>
    {% else %}
        <li><a href="{{ url_for('auth.login') }}">Sign In</a></li>
    {% endif %}
</ul>
11. 实现登录功能:app/auth/views.py
from flask import render_template, redirect, request, url_for, flash 
from flask_login import login_user
from . import auth
from ..models import User
from .forms import LoginForm

@auth.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user is not None and user.verify_password(form.password.data):
            login_user(user, form.remember_me.data)
            return redirect(request.args.get('next') or url_for('main.index'))
        flash('Invalid username or password.')
    return _render('login', locals())
12. 渲染登录页面: app/templates/auth/login.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}登录{% endblock %}
{% block page_content %}
    <div class="page-header">
        <h1>Login</h1>
    </div>
    <div class="col-md-4">
        {{ wtf.quick_form(form) }}
    </div>
{% endblock %}
13. 实现登出功能:app/auth/views.html
@auth.route('/logout')
@login_required
def logout():
    logout_user()
    flash('You have been logged out.')
    return redirect(url_for('main.index'))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容

  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,189评论 22 257
  • 大多数程序都需要进行用户跟踪。用户链接程序时需要进行身份认证,通过这一过程,让程序知道自己的身份。程序知道用户是谁...
    藕丝空间阅读 1,006评论 0 0
  • 第二部分 Blog例子 第八章 用户验证 大部分程序需要追踪用户身份。当用户连接到程序,通过一系列步骤使自己的身份...
    易木成华阅读 1,295评论 0 4
  • 一个完整的认证系统并不是简简单单的字符串相等,还应当考虑到安全性问题,比如用户的密码总不能直接暴露在数据库中吧,万...
    RickyLin7阅读 636评论 0 3
  • 最近在学习flask,用到flask-login,发现网上只有0.1版本的中文文档,看了官方已经0.4了,并且添加...
    ZZES_ZCDC阅读 5,956评论 3 24