flask中的flask-login

在这里插入图片描述

flask中的flask-login

在 Flask 中,用户认证通常是通过使用扩展库(例如 Flask-Login、Flask-HTTPAuth 或 Flask-Security)来实现的。

本文详细地解释下 Flask 中的用户认证。这里是用 Flask-Login 插件为例,这是一个处理用户会话的插件。首先,你需要安装 Flask-Login。你可以使用 pip 来安装:

pip install flask-login

接下来,在你的应用中初始化 Flask-Login:

from flask_login import LoginManagerlogin_manager = LoginManager()

然后,在创建 Flask 应用实例之后,你需要初始化 LoginManager:

app = Flask(__name__)
login_manager.init_app(app)

Flask-Login 要求你实现一个 callback 函数,这个函数接受一个用户 ID,并返回相应的用户对象。这可以通过 user_loader 装饰器来实现:

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

这里,User 是用户模型,它应该是一个数据库模型,用来存储用户信息。在 Flask 中,常常使用 SQLAlchemy 来管理数据库。一个简单的 User 模型可能如下所示:

from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()class User(UserMixin, db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(64), unique=True)password_hash = db.Column(db.String(128))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)

此处,我们还使用了 Werkzeug 提供的密码散列方法,为了保护用户的密码。

接下来,你需要创建一个登录页面。登录页面需要验证用户输入的用户名和密码:

from flask import render_template, redirect, url_for, flash
from flask_login import login_user
from your_form_file import LoginForm@app.route('/login', methods=['GET', 'POST'])
def login():form = LoginForm()if form.validate_on_submit():user = User.query.filter_by(username=form.username.data).first()if user is None or not user.check_password(form.password.data):flash('Invalid username or password')return redirect(url_for('login'))login_user(user)return redirect(url_for('index'))return render_template('login.html', form=form)

这里的 LoginForm 是一个 Flask-WTF 表单类,用来处理表单数据。

最后,你需要为用户登出设置路由:

from flask_login import logout_user@app.route('/logout')
def logout():logout_user()return redirect(url_for('index'))

在理解 Flask-Login 的执行流程之前,我们先需要理解几个关键的 Flask-Login 组件:

  1. LoginManager:它是 Flask-Login 的核心,负责管理用户会话。
  2. UserMixin:它为用户类提供默认的实现,如 is_authenticatedis_activeis_anonymousget_id
  3. user_loader:这是一个回调函数,当 Flask-Login 需要知道特定用户的信息时,会调用这个函数。这个函数应该接收一个用户 ID 作为输入,返回相应的用户对象。
  4. login_user:当用户在登录表单中提供了有效的凭证时,应用会调用这个函数,它会在用户会话中记录下该用户已登录。
  5. logout_user:当用户想要退出时,应用会调用这个函数,它会从用户会话中删除登录信息。

现在,我们来看一下 Flask-Login 的工作流程:

  1. 用户访问网站,发送一个请求到服务器。
  2. Flask 应用接收到请求,检查这个请求的会话中是否有用户 ID,如果有,那么 Flask-Login 会用这个 ID 调用 user_loader 回调函数,试图加载这个用户。
  3. 如果 user_loader 回调函数找到了用户,那么这个请求就是已认证的。如果没有找到用户,那么这个请求就是匿名的。
  4. 对于需要用户登录才能访问的视图函数,Flask-Login 会检查用户是否已认证。如果用户已认证,那么就允许访问。如果用户未认证,那么就重定向到登录页面。
  5. 在登录页面,用户会提供登录凭证,比如用户名和密码。服务器验证凭证,如果凭证有效,那么就调用 login_user 函数,记录用户已登录。
  6. 用户在浏览网站时,所有的请求都会带有用户的会话信息,所以服务器能知道是哪个用户发送的请求。
  7. 当用户决定退出时,应用会调用 logout_user 函数,删除用户的会话信息。

这就是 Flask-Login 的基本工作流程。它管理用户的登录状态,并提供一种简便的方式让你能在视图函数中访问当前用户。

补充1

Flask-Login 中的 user_loader 是一个回调函数,其执行时机主要在处理用户的请求时。每当用户发送一个请求到 Flask 应用时,Flask-Login 都会通过在用户会话(session)中存储的用户 ID 来执行 user_loader 函数,以获取对应的用户对象。

具体步骤如下:

  1. 当一个请求到达 Flask 应用时,Flask-Login 会先查看用户的会话中是否有用户 ID 存在。
  2. 如果用户会话中存在 ID,Flask-Login 就会调用 user_loader 函数,并把这个 ID 作为参数传入。
  3. user_loader 函数接收到这个 ID,然后查询数据库(或者其他存储用户数据的地方)找到对应的用户对象,并返回。
  4. Flask-Login 接着将这个用户对象存储在当前请求的上下文中,这样在处理这个请求的后续步骤中,你就可以使用 current_user 变量来访问这个用户对象了。

总的来说,user_loader 的调用是在每个请求开始时进行的,目的是为了从用户的会话中恢复用户对象,这样在处理请求时就可以知道是谁发起的请求,他/她是否有权限访问特定资源等等。

补充2

假设你有一个名为 dashboard 的视图函数,它只允许已认证的用户访问。你可以使用 Flask-Login 提供的 login_required 装饰器来实现这一点:

from flask_login import login_required@app.route('/dashboard')
@login_required
def dashboard():return render_template('dashboard.html')

如果一个已认证的用户尝试访问这个视图,他们将会正常地看到 dashboard 页面。然而,如果一个未认证的用户(例如,未登录或者会话已过期的用户)尝试访问这个视图,login_required 装饰器将会拦截这个请求,并重定向到登录页面。

你需要在 LoginManager 实例中设置登录视图的名称,以便 Flask-Login 知道未认证的用户应该被重定向到哪里:

login_manager.login_view = 'login'

这里 'login' 是登录视图函数的端点名。例如,如果你的登录视图函数像下面这样定义:

@app.route('/login', methods=['GET', 'POST'])
def login():# authentication code herepass

那么登录视图的端点名就是 ‘login’,所以上面的 login_manager.login_view = 'login' 表示未认证的用户将会被重定向到这个视图。

注意,你的登录视图函数应该处理两种请求方法:‘GET’ 和 ‘POST’。‘GET’ 请求用于显示登录表单,‘POST’ 请求用于提交表单。

补充3

这里我将为你展示一个简单的 Flask 登录页面的例子,这个例子使用了 Flask-Login 和 Flask-WTF(用于处理表单)。

首先,我们需要创建一个用于处理登录的表单类,如下:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequiredclass LoginForm(FlaskForm):username = StringField('Username', validators=[DataRequired()])password = PasswordField('Password', validators=[DataRequired()])submit = SubmitField('Sign In')

然后,我们需要创建一个处理登录的视图函数,代码如下:

from flask import render_template, redirect, url_for, flash
from flask_login import login_user
from .forms import LoginForm
from .models import User@app.route('/login', methods=['GET', 'POST'])
def login():form = LoginForm()if form.validate_on_submit():user = User.query.filter_by(username=form.username.data).first()if user is not None and user.check_password(form.password.data):login_user(user)return redirect(url_for('dashboard'))  #

补充4:用户注册

用户注册通常涉及到以下几个步骤:创建一个用户注册表单,创建一个处理用户提交注册信息的视图函数,以及创建一个用于显示注册表单的模板。

首先,我们需要创建一个用户注册表单,如下:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualToclass RegistrationForm(FlaskForm):username = StringField('Username', validators=[DataRequired()])password = PasswordField('Password', validators=[DataRequired()])confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])submit = SubmitField('Register')

然后,我们需要创建一个处理用户注册的视图函数,代码如下:

from flask import render_template, redirect, url_for, flash
from .forms import RegistrationForm
from .models import User, db@app.route('/register', methods=['GET', 'POST'])
def register():form = RegistrationForm()if form.validate_on_submit():user = User(username=form.username.data)user.set_password(form.password.data)db.session.add(user)db.session.commit()flash('Congratulations, you are now a registered user!')return redirect(url_for('login'))  # 登录页面的路由return render_template('register.html', form=form)

在这个视图函数中,当表单通过验证并提交时(form.validate_on_submit()),我们创建一个新的用户对象,并设置其密码(user.set_password(form.password.data))。然后,我们把新用户添加到数据库会话中,并提交会话以将数据写入数据库(db.session.add(user)db.session.commit())。最后,我们显示一个注册成功的消息,并重定向到登录页面。

最后,你需要在你的 ‘register.html’ 模板中添加一个显示注册表单的部分,代码可能如下:

<form method="POST">{{ form.hidden_tag() }}<p>{{ form.username.label }}<br>{{ form.username(size=20) }}</p><p>{{ form.password.label }}<br>{{ form.password(size=20) }}</p><p>{{ form.confirm_password.label }}<br>{{ form.confirm_password(size=20) }}</p><p>{{ form.submit() }}</p>
</form>

当用户在注册表单中输入用户名和密码并点击提交时,他们提供的数据将被发送到服务器进行处理。如果所有输入都满足验证规则(例如,两次输入的密码一致),一个新的用户就会被创建,并存储到数据库中。然后用户就会被重定向到登录页面。如果有任何验证失败,用户将被提示重新输入。

补充5:密码找回

密码找回功能的实现通常包括以下步骤:发送包含密码重置链接的电子邮件到用户的注册邮箱,用户点击链接后,被重定向到一个可以设置新密码的页面。

以下是一个简化的实现示例:

  1. 创建一个用于生成和验证密码重置令牌的用户模型方法

首先,在你的用户模型中,添加一个生成令牌的方法和一个验证令牌的方法。通常,可以使用 itsdangerous 库来生成签名的令牌。

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_appclass User(db.Model, UserMixin):# ...def get_reset_token(self, expires_sec=1800):s = Serializer(current_app.config['SECRET_KEY'], expires_sec)return s.dumps({'user_id': self.id}).decode('utf-8')@staticmethoddef verify_reset_token(token):s = Serializer(current_app.config['SECRET_KEY'])try:user_id = s.loads(token)['user_id']except:return Nonereturn User.query.get(user_id)
  1. 创建一个发送密码重置电子邮件的函数

接下来,你需要创建一个函数,该函数生成一个密码重置令牌,然后发送一封包含密码重置链接的电子邮件到用户的注册邮箱。这个链接应该包含令牌作为查询参数。

你可能会使用 Flask-Mail 插件来发送邮件。

  1. 创建密码重置请求的视图函数

创建一个视图函数来处理密码重置请求,获取用户输入的电子邮件地址,查找关联的用户,如果找到了用户,就调用上面的函数来发送密码重置电子邮件。

  1. 创建处理密码重置链接的视图函数

创建一个视图函数来处理用户点击密码重置链接后的请求。这个视图函数应该从链接的查询参数中获取令牌,然后调用用户模型的 verify_reset_token 方法来验证令牌。如果验证通过,将用户重定向到一个可以输入新密码的表单页面。

  1. 创建设置新密码的视图函数

最后,你需要创建一个视图函数来处理用户提交新密码的请求。这个视图函数应该获取用户的新密码,然后更新用户模型中的密码字段,最后把更新后的用户数据存回数据库。

这个流程需要用户能够接收和发送电子邮件,并且你的应用能够发送电子邮件。这个流程在某些方面可能需要调整以适应你的具体需求,例如邮件服务的选择,以及如何处理邮件发送失败的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/55994.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

建筑行业如果应用了数字孪生技术能有什么改变?

数字孪生是一种将现实世界与数字世界相结合的先进技术&#xff0c;它在建筑行业中正发挥着越来越重要的作用。通过数字孪生技术&#xff0c;建筑行业可以实现从设计、施工到运营的全生命周期数字化管理&#xff0c;带来了许多优势和机遇。 ① 建筑设计阶段的应用 数字孪生能够…

比较 Java Enterprise Architecture 中的 MongoDB 和 Couchbase

​MongoDB和Couchbase是两种常用的NoSQL数据库&#xff0c;用于在Java实现的企业架构中存储和管理数据。以下是它们之间的主要差异、比较和权衡。 在当今快速发展的企业架构领域&#xff0c;MongoDB和Couchbase已经成为NoSQL数据库中两个重要的竞争者。本文全面探讨了这两个强…

24数据结构-图的基本概念与存储结构

目录 第六章 图6.1 图的基本概念知识回顾 6.2 图的储存结构&#xff08;邻接矩阵法&#xff09;1. 数组表示法(1) 有向图&#xff0c;无向图的邻接矩阵 2. 定义邻接矩阵的结构3. 定义图的结构4. 构造图G5. 特点 第六章 图 6.1 图的基本概念 图是一种非线性结构 图的特点&am…

使用node.js 搭建一个简单的HelloWorld Web项目

文档结构 config.ini #将本文件放置于natapp同级目录 程序将读取 [default] 段 #在命令行参数模式如 natapp -authtokenxxx 等相同参数将会覆盖掉此配置 #命令行参数 -config 可以指定任意config.ini文件 [default] authtokencc83c08d73357802 #对应一条隧…

LeetCode 热题 100 JavaScript--234. 回文链表

function ListNode(val, next) {this.val val undefined ? 0 : val;this.next next undefined ? null : next; }var isPalindrome function (head) {if (!head || !head.next) {return true; }// 使用快慢指针法找到链表的中间节点let slow head;let fast head;while …

快速WordPress个人博客并内网穿透发布到互联网

文章目录 我们能够通过cpolar完整的搭建起一个属于自己的网站&#xff0c;并且通过cpolar建立的数据隧道&#xff0c;从而让我们存放在本地电脑上的网站&#xff0c;能够为公众互联网的用户访问。大量的测试和试运行&#xff0c;难免让人觉得眼花缭乱。今天&#xff0c;我们就抛…

SQL ASNI where from group order 顺序

SQL语句执行顺序&#xff1a; from–>where–>group by -->having — >select --> order 第一步&#xff1a;from语句&#xff0c;选择要操作的表。 第二步&#xff1a;where语句&#xff0c;在from后的表中设置筛选条件&#xff0c;筛选出符合条件的记录。 …

数据结构 | 树的定义及实现

目录 一、树的术语及定义 二、树的实现 2.1 列表之列表 2.2 节点与引用 一、树的术语及定义 节点&#xff1a; 节点是树的基础部分。它可以有自己的名字&#xff0c;我们称作“键”。节点也可以带有附加信息&#xff0c;我们称作“有效载荷”。有效载荷信息对于很多树算法…

The ‘kotlin-android-extensions‘ Gradle plugin is no longer supported.

Android使用kotlin开发&#xff0c;运行报错 The kotlin-android-extensions Gradle plugin is no longer supported. Please use this migration guide (https://goo.gle/kotlin-android-extensions-deprecation) to start working with View Binding (https://developer.an…

【MFC】05.MFC第一大机制:程序启动机制-笔记

MFC程序开发所谓是非常简单&#xff0c;但是对于我们逆向人员来说&#xff0c;如果想要逆向MFC程序&#xff0c;那么我们就必须了解它背后的机制&#xff0c;这样我们才能够清晰地逆向出MFC程序&#xff0c;今天这篇文章就来带领大家了解MFC的第一大机制&#xff1a;程序启动机…

Transformer1.0-预热

一.Encoder encoder:译为编码器&#xff0c;负责将输入序列压缩成指定长度的向量&#xff0c;这个向量就可以堪称是这个序列的语义。然后可进行编码或特征提取等操作 在transformer中encoder由6个相同的层组成&#xff0c;每个层包含 Multi-Head Self-AttentionPosition-Wise …

day50-springboot+ajax分页

分页依赖&#xff1a; <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency> 配置&#xff1a; …