Flask 扩展 用户会话

2023-11-09

pip install flask-login

接下来创建扩展对象实例:

from flask import Flask
from flask_login import LoginManager
 
app = Flask(__name__)
login_manager = LoginManager(app)

同时,你可以对LoginManager对象赋上配置参数:

# 设置登录视图的名称,如果一个未登录用户请求一个只有登录用户才能访问的视图,
# 则闪现一条错误消息,并重定向到这里设置的登录视图。
# 如果未设置登录视图,则直接返回401错误。
login_manager.login_view = 'login'
# 设置当未登录用户请求一个只有登录用户才能访问的视图时,闪现的错误消息的内容,
# 默认的错误消息是:Please log in to access this page.。
login_manager.login_message = 'Unauthorized User'
# 设置闪现的错误消息的类别
login_manager.login_message_category = "info"

编写用户类

使用Flask-Login之前,你需要先定义用户类,该类必须实现以下三个属性和一个方法:

属性 is_authenticated

  当用户登录成功后,该属性为True。

属性 is_active

  如果该用户账号已被激活,且该用户已登录成功,则此属性为True。

属性 is_anonymous

  是否为匿名用户(未登录用户)。

方法 get_id()

  每个用户都必须有一个唯一的标识符作为ID,该方法可以返回当前用户的ID,这里ID必须是Unicode。

因为每次写个用户类很麻烦,Flask-Login提供了”UserMixin”类,你可以直接继承它即可:

from flask_login import UserMixin
 
class User(UserMixin):
    pass

从会话或请求中加载用户

在编写登录登出视图前,我们要先写一个加载用户对象的方法。它的功能是根据传入的用户ID,构造一个新的用户类的对象。为了简化范例,我们不引入数据库,而是在列表里定义用户记录。

# 用户记录表
users = [
    {'username': 'Tom', 'password': '111111'},
    {'username': 'Michael', 'password': '123456'}
]
 
# 通过用户名,获取用户记录,如果不存在,则返回None
def query_user(username):
    for user in users:
        if user['username'] == username:
            return user
 
# 如果用户名存在则构建一个新的用户类对象,并使用用户名作为ID
# 如果不存在,必须返回None
@login_manager.user_loader
def load_user(username):
    if query_user(username) is not None:
        curr_user = User()
        curr_user.id = username
        return curr_user

上述代码中,通过”@login_manager.user_loader”装饰器修饰的方法,既是我们要实现的加载用户对象方法。它是一个回调函数,在每次请求过来后,Flask-Login都会从Session中寻找”user_id”的值,如果找到的话,就会用这个”user_id”值来调用此回调函数,并构建一个用户类对象。因此,没有这个回调的话,Flask-Login将无法工作。

有一个问题,启用Session的话一定需要客户端允许Cookie,因为Session ID是保存在Cookie中的,如果Cookie被禁用了怎么办?那我们的应用只好通过请求参数将用户信息带过来,一般情况下会使用一个动态的Token来表示登录用户的信息。此时,我们就不能依靠”@login_manager.user_loader”回调,而是使用”@login_manager.request_loader”回调。

from flask import request
 
# 从请求参数中获取Token,如果Token所对应的用户存在则构建一个新的用户类对象
# 并使用用户名作为ID,如果不存在,必须返回None
@login_manager.request_loader
def load_user_from_request(request):
    username = request.args.get('token')
    if query_user(username) is not None:
        curr_user = User()
        curr_user.id = username
        return curr_user

为了简化代码,上面的例子就直接使用用户名作为Token了,实际项目中,大家还是要用一个复杂的算法来验证Token。

登录及登出

一切准备就绪,我们开始实现登录视图:

from flask import render_template, redirect, url_for, flash
from flask_login import login_user
 
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        user = query_user(username)
        # 验证表单中提交的用户名和密码
        if user is not None and request.form['password'] == user['password']:
            curr_user = User()
            curr_user.id = username
 
            # 通过Flask-Login的login_user方法登录用户
            login_user(curr_user)
 
            # 如果请求中有next参数,则重定向到其指定的地址,
            # 没有next参数,则重定向到"index"视图
            next = request.args.get('next')
            return redirect(next or url_for('index'))
 
        flash('Wrong username or password!')
    # GET 请求
    return render_template('login.html')

上述代码同之前Login视图最大的不同就是你在用户验证通过后,需要调用Flask-Login扩展提供的”login_user()”方法来让用户登录,该方法需传入用户类对象。这个”login_user()”方法会帮助你操作用户Session,并且会在请求上下文中记录用户信息。另外,在具体实现时,建议大家对”next”参数值作验证,避免被URL注入攻击。

“login.html”模板很简单,就是显示一个用户名密码的表单:

<!doctype html>
<title>Login Sample</title>
<h1>Login</h1>
{% with messages = get_flashed_messages() %}
    <div>{{ messages[0] }}</div>
{% endwith %}
<form action="{{ url_for('login') }}" method="POST">
    <input type="text" name="username" id="username" placeholder="Username"></input>
    <input type="password" name="password" id="password" placeholder="Password"></input>
    <input type="submit" name="submit"></input>
</form>

接下来,让我们写个index视图

from flask_login import current_user, login_required
 
@app.route('/')
@login_required
def index():
    return 'Logged in as: %s' % current_user.get_id()

装饰器”@login_required”确保只有登录用户才能访问这个index视图,Flask-Login帮我们实现了这个装饰器。如果用户未登录,它就会将页面重定向到登录视图,也就是我们在第一节中配置的”login_manager.login_view”的视图。

同时,重定向的地址会自动加上”next”参数,参数的值是当前用户请求的地址,这样,登录成功后就会跳转回当前视图。可以看到我们对于用户登录所需要的操作,这个装饰器基本都实现了

 

Flask-Login还提供了”current_user”代理,可以访问到登录用户的用户类对象。我们在模板中也可以使用这个代理。让我们再写一个home视图:

@app.route('/home')
@login_required
def home():
    return render_template('hello.html')

模板代码如下:

<!doctype html>
<title>Login Sample</title>
{% if current_user.is_authenticated %}
  <h1>Hello {{ current_user.get_id() }}!</h1>
{% endif %}

在上面的模板代码中,我们直接访问了”current_user”对象的属性和方法。

登出视图也很简单,Flask-Login提供了”logout_user()”方法来帮助你清理用户Session。

from flask_login import logout_user
 
@app.route('/logout')
@login_required
def logout():
    logout_user()
    return 'Logged out successfully!'

自定义未授权访问的处理方法

“@login_required”装饰器对于未登录用户访问的默认处理是重定向到登录视图,如果我们不想它这么做的话,可以自定义处理方法:

@login_manager.unauthorized_handler
def unauthorized_handler():
    return 'Unauthorized'

这个”@login_manager.unauthorized_handler”装饰器所修饰的方法就会代替”@login_required”装饰器的默认处理方法。有了上面的代码,当未登录用户访问index视图时,页面就会直接返回”Unauthorized”信息。

Remember Me

在登录视图中,调用”login_user()”方法时,传入”remember=True”参数,即可实现“记住我”功能:

...
            login_user(curr_user, remember=True)
...

Flask-Login是通过在Cookie实现的,它会在Cookie中添加一个”remember_token”字段来记住之前登录的用户信息,所以禁用Cookie的话,该功能将无法工作。

Fresh登录

当用户通过账号和密码登录后,Flask-Login会将其标识为Fresh登录,即在Session中设置”_fresh”字段为True。而用户通过Remember Me自动登录的话,则不标识为Fresh登录。对于”@login_required”装饰器修饰的视图,是否Fresh登录都可以访问,但是有些情况下,我们会强制要求用户登录一次,比如修改登录密码,这时候,我们可以用”@fresh_login_required”装饰器来修饰该视图。这样,通过Remember Me自动登录的用户,将无法访问该视图:

from flask_login import fresh_login_required
 
@app.route('/home')
@fresh_login_required
def home():
    return 'Logged in as: %s' % current_user.get_id()

会话保护

Flask-Login自动启用会话保护功能。对于每个请求,它会验证用户标识,这个标识是由客户端IP地址和User Agent的值经SHA512编码而来。在用户登录成功时,Flask-Login就会将这个值保存起来以便后续检查。默认的会话保护模式是”basic”,为了加强安全性,你可以启用强会话保护模式,方法是配置LoginManager实例对象中的”session_protection”属性:

login_manager.session_protection = "strong"

在”strong”模式下,一旦用户标识检查失败,便会清空所用Session内容,并且Remember Me也失效。而”basic”模式下,只是将登录标为非Fresh登录。你还可以将”login_manager.session_protection”置为None来取消会话保护。

 

转载于:https://www.cnblogs.com/Erick-L/p/7057694.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flask 扩展 用户会话 的相关文章

随机推荐

  • 第8章 Stata主成分分析与因子分析

    目录 8 1主成分分析 8 2因子分析 1 主成因子法 2 主因子法 3 迭代公因子方差的主因子法 4 最大似然因子法 在进行数据统计分析时 还往往会遇见变量特别多的情况 而且很多时候这些变量之间还存在着很强的相关关系或者说变量之间存在着很
  • 万字长文深入浅出理解ChatGPT工作原理

    本文转自 原创 万字长文深入浅出理解ChatGPT工作原理 qq com AIGC简要介绍 AIGC是什么 AIGC AI Generated Content AI生成内容 对应我们的过去的主要是 UGC User Generated Co
  • 如何通过Anaconda创建虚拟环境

    做深度学习的同学们应该都受到配置环境的困扰 我也是饱受摧残 本文介绍几个踩过的坑 在anaconda下创建一个虚拟环境 文件名为 pytorch python版本是 3 8 conda create n pytorch python 3 8
  • 【GIT 使用教程 linux 环境】

    1 GIT基本使用 1 linux环境下安装GIT sudo apt get install git 2 全局账号配置 git config global user name yourname git config global user
  • vue v-for循环

    vue v for循环中通过一个变量控制不同的下拉框 默认是全部展开 当点击每个表格的下拉图标 就会显示或隐藏 刚开始做的时候就通过一个变量进行控制 导致点击一个下拉图标就会控制所有有的表格下拉 所以应该是给每个表格对应的集合中加一条属性来
  • autojs常见报错及解决

    autojs常见报错及解决 期待大家在下面评论补充 更多基础加autojs交流群553908361喽 一键加群 点击加群 1 需要在ui模式下运行才能使用该函数 file android asset modules ui js 15 Err
  • Antv/G2 柱状图

    Antv G2 教程 G2 是一套基于图形语法理论的可视化底层引擎 以数据驱动 提供图形语法与交互语法 具有高度的易用性和扩展性 使用 G2 无需关注图表各种繁琐的实现细节 一条语句即可使用 Canvas 或 SVG 构建出各种各样的可交互
  • MacbookPro M1芯片对“cp -r” 命令支持有误,慎重购买

    MacBook2021 M1 MAXPro电脑问题锦集 问题1 开启硬盘加密 开机闪屏 问题详述 在系统偏好设置中 打开安全与隐私 在弹出窗口中切换到第二个页签 文件保险箱 启用文件保险箱功能 然后关机重新启动电脑 在输入密码回车后进度条刚
  • 开发时写TestCase的一些经验

    今天修复完一个业务代码的 bug 手动测试没有问题 但写测试用例出错 在对代码很自信的情况下 因为手动测试过了 我干脆省略了这个步骤 然而偷懒的事情早晚会暴露出来 用 Git 提交到远程时在 Code Review 那里的系统集成测试老是失
  • 【SVM回归预测】基于支持向量机的数据回归预测(libsvm)附matlab代码

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab仿真内容点击 智能优化算法 神经网络预测 雷达通信
  • 如何处理企业间的人际关系

    如何处理企业之间的人际关系呢 其实这个话题很多人一直都迷茫 包括我在内 我也还没有学会如何处理企业之间的人际关系 这是一门大学问 可惜真正写文章的人没有感受 会写文章的人表达不出来 所以都比较少看到诸类的文章 即使有类似的文章 可是以理论化
  • 说一说xgboost和lightgbm的区别是什么

    前面提到了 LightGBM是Xgboost的更高效实现 由微软发布 XGBoost的并行是在特征粒度上的 我们知道 决策树的学习最耗时的一个步骤就是对特征的值进行排序 因为要确定最佳分割点 XGBoost在训练之前 预先对数据进行了排序
  • JAVA 基础题

    1 面向对象有哪些特征 答 继承 封装 多态 2 JDK与JRE的区别是什么 答 JDK是java开发时所需环境 它包含了Java开发时需要用到的API JRE是Java的运行时环境 JDK包含了JRE 他们是包含关系 3 Java有哪几种
  • Umask的含义

    Umask的含义 umask 022中 022 是八进制的写法 如果换成二进制是000010010 在unix中文件权限是三类用户 三种权限 三类用户分别是文件所有者user u 文件所有者所在主群组group g 其它用户others o
  • Vue脚手架安装和初次使用

    1 安装淘宝镜像 npm config set registry https registry npm taobao org 2 全局安装脚手架 npm install g vue cli 3 切到要创建项目的目录 创建项目 本例选择目录为
  • windows DHCP服务器部署

    目录 一 关于windows dhcp服务器 1 1 关于dhcp 1 2 DHCP续约 二 DHCP服务器部署 2 1 关于DHCP服务器 2 2部署DHCP服务器 2 3 保留特定IP地址 2 4 相关dos命令使用 2 5 多个地址池
  • 如何在Mac OS上从Photoshop 2020作为插件访问Topaz DeNoise AI?

    TopazDeNoise AI for mac是Topaz系列中的一款AI图像降噪软件 topaz denoise ai破解版提供了数百万个噪声 清晰图像的算法 可以快速消除图像中噪音并且保留原始图像细节 人工智能降噪Topaz DeNoi
  • [Python从零到壹] 六十七.图像识别及经典案例篇之基于卷积神经网络的MNIST图像分类

    七月太忙 还是写一篇吧 欢迎大家来到 Python从零到壹 在这里我将分享约200篇Python系列文章 带大家一起去学习和玩耍 看看Python这个有趣的世界 所有文章都将结合案例 代码和作者的经验讲解 真心想把自己近十年的编程经验分享给
  • 如何从RNN起步,一步一步通俗理解LSTM

    转自 https blog csdn net v july v article details 89894058 如何从RNN起步 一步一步通俗理解LSTM 前言 提到LSTM 之前学过的同学可能最先想到的是ChristopherOlah的
  • Flask 扩展 用户会话

    pip install flask login 接下来创建扩展对象实例 from flask import Flask from flask login import LoginManager app Flask name login ma