当前位置: 首页 > article >正文

Flask-Login使用示例

项目结构

首先创建以下文件结构:

flask_login_use/
├── app.py
├── models.py
├── requirements.txt
└── templates/├── base.html├── index.html├── login.html├── register.html└── profile.html

1. requirements.txt

Flask==2.3.3
Flask-Login==0.6.3
Flask-WTF==1.1.1
WTForms==3.0.1
Werkzeug==2.3.7
email_validator

2. models.py - 用户模型

from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hashclass User(UserMixin):def __init__(self, id, username, email, password_hash):self.id = idself.username = usernameself.email = emailself.password_hash = password_hashdef check_password(self, password):return check_password_hash(self.password_hash, password)@staticmethoddef create_password_hash(password):return generate_password_hash(password)# 模拟数据库存储
users_db = {}
next_user_id = 1def get_user(user_id):return users_db.get(int(user_id))def get_user_by_username(username):for user in users_db.values():if user.username == username:return userreturn Nonedef create_user(username, email, password):global next_user_idpassword_hash = User.create_password_hash(password)user = User(next_user_id, username, email, password_hash)users_db[next_user_id] = usernext_user_id += 1return user

3. app.py - 主应用文件

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, Length, EqualTo
from models import User, get_user, get_user_by_username, create_userapp = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'  # 在生产环境中使用更安全的密钥# 初始化Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
login_manager.login_message = '请先登录以访问此页面。'
login_manager.login_message_category = 'info'@login_manager.user_loader
def load_user(user_id):return get_user(user_id)# 表单类
class LoginForm(FlaskForm):username = StringField('用户名', validators=[DataRequired()])password = PasswordField('密码', validators=[DataRequired()])submit = SubmitField('登录')class RegisterForm(FlaskForm):username = StringField('用户名', validators=[DataRequired(), Length(min=4, max=20, message='用户名长度必须在4-20个字符之间')])email = StringField('邮箱', validators=[DataRequired(), Email(message='请输入有效的邮箱地址')])password = PasswordField('密码', validators=[DataRequired(), Length(min=6, message='密码长度至少6个字符')])password2 = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password', message='两次输入的密码不一致')])submit = SubmitField('注册')# 路由
@app.route('/')
def index():return render_template('index.html')@app.route('/login', methods=['GET', 'POST'])
def login():if current_user.is_authenticated:return redirect(url_for('index'))form = LoginForm()if form.validate_on_submit():user = get_user_by_username(form.username.data)if user and user.check_password(form.password.data):login_user(user)flash('登录成功!', 'success')# 获取用户尝试访问的页面next_page = request.args.get('next')return redirect(next_page) if next_page else redirect(url_for('index'))else:flash('用户名或密码错误', 'danger')return render_template('login.html', form=form)@app.route('/register', methods=['GET', 'POST'])
def register():if current_user.is_authenticated:return redirect(url_for('index'))form = RegisterForm()if form.validate_on_submit():# 检查用户名是否已存在if get_user_by_username(form.username.data):flash('用户名已存在', 'danger')else:# 创建新用户user = create_user(username=form.username.data,email=form.email.data,password=form.password.data)flash('注册成功!请登录。', 'success')return redirect(url_for('login'))return render_template('register.html', form=form)@app.route('/logout')
@login_required
def logout():logout_user()flash('您已成功登出', 'info')return redirect(url_for('index'))@app.route('/profile')
@login_required
def profile():return render_template('profile.html')@app.route('/protected')
@login_required
def protected():return f'<h1>受保护的页面</h1><p>你好,{current_user.username}!这是一个需要登录才能访问的页面。</p><a href="{url_for("index")}">返回首页</a>'if __name__ == '__main__':app.run(debug=True)

4. 模板文件

base.html - 基础模板

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>{% block title %}Flask-Login 示例{% endblock %}</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body><nav class="navbar navbar-expand-lg navbar-dark bg-dark"><div class="container"><a class="navbar-brand" href="{{ url_for('index') }}">Flask-Login 示例</a><div class="navbar-nav ms-auto">{% if current_user.is_authenticated %}<a class="nav-link" href="{{ url_for('profile') }}">个人资料</a><a class="nav-link" href="{{ url_for('protected') }}">受保护页面</a><a class="nav-link" href="{{ url_for('logout') }}">登出 ({{ current_user.username }})</a>{% else %}<a class="nav-link" href="{{ url_for('login') }}">登录</a><a class="nav-link" href="{{ url_for('register') }}">注册</a>{% endif %}</div></div></nav><div class="container mt-4">{% with messages = get_flashed_messages(with_categories=true) %}{% if messages %}{% for category, message in messages %}<div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show" role="alert">{{ message }}<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>{% endfor %}{% endif %}{% endwith %}{% block content %}{% endblock %}</div><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

index.html - 首页

{% extends "base.html" %}{% block content %}
<div class="row"><div class="col-md-8 mx-auto"><div class="jumbotron bg-light p-5 rounded"><h1 class="display-4">欢迎使用 Flask-Login 示例</h1><p class="lead">这是一个演示 Flask-Login 功能的完整示例应用。</p>{% if current_user.is_authenticated %}<h4>你好,{{ current_user.username }}!</h4><p>你已经成功登录。你可以:</p><ul><li><a href="{{ url_for('profile') }}">查看个人资料</a></li><li><a href="{{ url_for('protected') }}">访问受保护的页面</a></li><li><a href="{{ url_for('logout') }}">登出</a></li></ul>{% else %}<p>请先登录或注册以体验完整功能。</p><a class="btn btn-primary btn-lg" href="{{ url_for('login') }}" role="button">登录</a><a class="btn btn-secondary btn-lg" href="{{ url_for('register') }}" role="button">注册</a>{% endif %}</div></div>
</div>
{% endblock %}

login.html - 登录页面

{% extends "base.html" %}{% block title %}登录 - Flask-Login 示例{% endblock %}{% block content %}
<div class="row"><div class="col-md-6 mx-auto"><div class="card"><div class="card-header"><h3>登录</h3></div><div class="card-body"><form method="POST">{{ form.hidden_tag() }}<div class="mb-3">{{ form.username.label(class="form-label") }}{{ form.username(class="form-control") }}{% if form.username.errors %}<div class="text-danger">{% for error in form.username.errors %}<small>{{ error }}</small>{% endfor %}</div>{% endif %}</div><div class="mb-3">{{ form.password.label(class="form-label") }}{{ form.password(class="form-control") }}{% if form.password.errors %}<div class="text-danger">{% for error in form.password.errors %}<small>{{ error }}</small>{% endfor %}</div>{% endif %}</div><div class="d-grid">{{ form.submit(class="btn btn-primary") }}</div></form><div class="text-center mt-3"><p>还没有账户? <a href="{{ url_for('register') }}">立即注册</a></p></div></div></div></div>
</div>
{% endblock %}

register.html - 注册页面

{% extends "base.html" %}{% block title %}注册 - Flask-Login 示例{% endblock %}{% block content %}
<div class="row"><div class="col-md-6 mx-auto"><div class="card"><div class="card-header"><h3>注册</h3></div><div class="card-body"><form method="POST">{{ form.hidden_tag() }}<div class="mb-3">{{ form.username.label(class="form-label") }}{{ form.username(class="form-control") }}{% if form.username.errors %}<div class="text-danger">{% for error in form.username.errors %}<small>{{ error }}</small>{% endfor %}</div>{% endif %}</div><div class="mb-3">{{ form.email.label(class="form-label") }}{{ form.email(class="form-control") }}{% if form.email.errors %}<div class="text-danger">{% for error in form.email.errors %}<small>{{ error }}</small>{% endfor %}</div>{% endif %}</div><div class="mb-3">{{ form.password.label(class="form-label") }}{{ form.password(class="form-control") }}{% if form.password.errors %}<div class="text-danger">{% for error in form.password.errors %}<small>{{ error }}</small>{% endfor %}</div>{% endif %}</div><div class="mb-3">{{ form.password2.label(class="form-label") }}{{ form.password2(class="form-control") }}{% if form.password2.errors %}<div class="text-danger">{% for error in form.password2.errors %}<small>{{ error }}</small>{% endfor %}</div>{% endif %}</div><div class="d-grid">{{ form.submit(class="btn btn-success") }}</div></form><div class="text-center mt-3"><p>已有账户? <a href="{{ url_for('login') }}">立即登录</a></p></div></div></div></div>
</div>
{% endblock %}

profile.html - 个人资料页面

{% extends "base.html" %}{% block title %}个人资料 - Flask-Login 示例{% endblock %}{% block content %}
<div class="row"><div class="col-md-8 mx-auto"><div class="card"><div class="card-header"><h3>个人资料</h3></div><div class="card-body"><table class="table"><tr><th>用户ID:</th><td>{{ current_user.id }}</td></tr><tr><th>用户名:</th><td>{{ current_user.username }}</td></tr><tr><th>邮箱:</th><td>{{ current_user.email }}</td></tr><tr><th>登录状态:</th><td>{% if current_user.is_authenticated %}<span class="badge bg-success">已登录</span>{% else %}<span class="badge bg-danger">未登录</span>{% endif %}</td></tr></table><div class="mt-3"><a href="{{ url_for('index') }}" class="btn btn-primary">返回首页</a><a href="{{ url_for('logout') }}" class="btn btn-danger">登出</a></div></div></div></div>
</div>
{% endblock %}

运行应用

  1. 安装依赖:
pip install -r requirements.txt
  1. 运行应用:
python app.py
  1. 在浏览器中访问 http://localhost:5000

或者用uv来控制项目:
在这里插入图片描述

在这里插入图片描述

页面测试:
在这里插入图片描述
❤️➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖❤️

在这里插入图片描述

❤️➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖❤️
在这里插入图片描述
❤️➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖❤️

在这里插入图片描述
❤️➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖❤️

在这里插入图片描述
❤️➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖❤️

在这里插入图片描述

相关文章:

Flask-Login使用示例

项目结构 首先创建以下文件结构&#xff1a; flask_login_use/ ├── app.py ├── models.py ├── requirements.txt └── templates/├── base.html├── index.html├── login.html├── register.html└── profile.html1. requirements.txt Flask2.3.3 Fl…...

React Hooks 基础指南

React Hooks 是 React 16.8 引入的重要特性&#xff0c;它允许开发者在函数组件中使用状态和其他 React 特性。本文将详细介绍 6 个最常用的 React Hooks。 1. useState useState 是最常用的 Hook&#xff0c;用于在函数组件中添加 state。 import React, { useState } from…...

web第九次课后作业--SpringBoot基于mybatis实现对数据库的操作

前言 在前面我们学习MySQL数据库时&#xff0c;都是利用图形化客户端工具(如&#xff1a;idea、datagrip)&#xff0c;来操作数据库的。 在客户端工具中&#xff0c;编写增删改查的SQL语句&#xff0c;发给MySQL数据库管理系统&#xff0c;由数据库管理系统执行SQL语句并返回执…...

沪铜6月想法

市场回顾 2025年5月&#xff0c;沪铜期货主力合约价格整体呈现震荡走势。从月初到月末&#xff0c;价格在7.67-7.82万元/吨之间波动。截至5月31日&#xff0c;沪铜主力合约收盘价为7.76万元/吨。本月铜价围绕供需基本面和宏观政策预期展开波动&#xff0c;尤其在5月14日至5月1…...

网络通信核心概念全解析:从IP地址到TCP/UDP实战

一、网络基础架构三要素 1. IP地址&#xff1a;互联网的“门牌号” 本质&#xff1a;32位整数标识主机位置&#xff08;IPv4&#xff09;表示法&#xff1a;点分十进制&#xff08;如 192.168.1.1&#xff09;功能&#xff1a;全球唯一标识网络设备特殊地址&#xff1a; 127.…...

Spring 中的disposableBean介绍

在 Spring 框架中&#xff0c;DisposableBean 是一个接口&#xff0c;用于定义 Bean 在被销毁前需要执行的清理逻辑。它是 Spring 容器生命周期回调机制的一部分。 &#x1f331; 什么是 DisposableBean DisposableBean 接口是 Spring 提供的一个标准接口&#xff0c;用于通知…...

【Linux命令学习】获取cpu信息 - lscpu命令学习

lscpu命令显示的是服务器cpu架构相关信息&#xff0c;lscpu从伪文件系统(sysfs)、/proc/cpuinfo和任何可用的特定体系架构库中收集cpu架构信息。输出内容包括&#xff1a;CPU、线程、内核的数量以及非同一存储器存取节点。此外还包括关于CPU高速缓存和高速缓存共享的信息&#…...

wordpress免费主题网站

这是一款WordPress主题&#xff0c;由jianzhanpress开发&#xff0c;可以免费下载。专为中小微企业设计&#xff0c;提供专业的网站建设、网站运营维护、网站托管和网站优化等服务。主题设计简约、现代&#xff0c;适合多种行业需求。 主要特点&#xff1a; 多样化展示&#…...

Go中的协程并发和并发panic处理

1 协程基础 1.1 协程定义&#xff08;Goroutine&#xff09; 概念&#xff1a;Go 语言特有的轻量级线程&#xff0c;由 Go 运行时&#xff08;runtime&#xff09;管理&#xff0c;相比系统线程&#xff08;Thread&#xff09;&#xff0c;创建和销毁成本极低&#xff0c;占用…...

Qt Creator工具编译器配置

1、打开Qt Creator&#xff0c;工具-->选项 2、选择"编译器"&#xff0c;Manual配置编译器。 初始化填入“C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\cl.exe”&#xff0c;选择64位amd64。 ABI根据msvc版本进行选择msvc2015. 3、新建项目…...

从零开始的数据结构教程(六) 贪心算法

&#x1f36c; 标题一&#xff1a;贪心核心思想——发糖果时的最优分配策略 贪心算法 (Greedy Algorithm) 是一种简单直观的算法策略。它在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望得到一个全局最优解。这就像你…...

Spring框架学习day7--SpringWeb学习(概念与搭建配置)

SpringWeb1.SpringWeb特点2.SpringWeb运行流程3.SpringWeb组件4.搭建项目结构图&#xff1a;4.1导入jar包4.2在Web.xml配置**4.2.1配置统一拦截分发器 DispatcherServlet**4.2.2开启SpringWeb注解&#xff08;spring.xml&#xff09; 5.处理类的搭建6.SpringWeb请求流程(自己理…...

打造高效多模态RAG系统:原理与评测方法详解

引言 随着信息检索与生成式AI的深度融合&#xff0c;检索增强生成&#xff08;RAG, Retrieval-Augmented Generation&#xff09; 已成为AI领域的重要技术方向。传统RAG系统主要依赖文本数据&#xff0c;但真实世界中的信息往往包含图像、表格等多模态内容。多模态RAG&#xf…...

SSM 框架核心知识详解(Spring + SpringMVC + MyBatis)

&#x1f331; 第一部分&#xff1a;Spring 核心原理与使用 1. 什么是 Spring Spring 是一个开源的 Java 企业级开发框架&#xff0c;旨在简化 Java 企业应用程序开发。它核心思想是控制反转&#xff08;IoC&#xff09;和面向切面编程&#xff08;AOP&#xff09;&#xff0…...

1.2 fetch详解

浏览器 Fetch API 详解 Fetch API 是现代浏览器提供的用于发起网络请求的接口&#xff0c;它基于 Promise 实现&#xff0c;替代了传统的 XMLHttpRequest&#xff0c;提供了更强大、更灵活的功能。 1. 基本用法 使用 fetch() 函数发起请求&#xff0c;返回一个 Promise&…...

【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…...

02 Deep learning神经网络的编程基础 逻辑回归--吴恩达

逻辑回归 逻辑回归是一种用于解决二分类任务&#xff08;如预测是否是猫咪等&#xff09;的统计学习方法。尽管名称中包含“回归”&#xff0c;但其本质是通过线性回归的变体输出概率值&#xff0c;并使用Sigmoid函数将线性结果映射到[0,1]区间。 以猫咪预测为例 假设单个样…...

Android Native 内存泄漏检测全解析:从原理到工具的深度实践

引言 Android应用的内存泄漏不仅发生在Java/Kotlin层&#xff0c;Native&#xff08;C/C&#xff09;层的泄漏同样普遍且隐蔽。由于Native内存不受Java虚拟机&#xff08;JVM&#xff09;管理&#xff0c;泄漏的内存无法通过GC自动回收&#xff0c;长期积累会导致应用内存占用…...

React---扩展补充

一些额外的扩展 4.3 高阶组件 高阶组件是参数为组件&#xff0c;返回值为新组件的函数&#xff1b; 高阶组件 本身不是一个组件&#xff0c;而是一个函数&#xff1b;其次&#xff0c;这个函数的参数是一个组件&#xff0c;返回值也是一个组件&#xff1b; import React fr…...

HTML 中 class 属性介绍、用法

1、&#x1f516; 什么是 class class 是 HTML 元素的一个核心属性&#xff0c;用来为元素指定一个或多个类名。它在网页开发中承担三大作用&#xff1a; &#x1f3a8; 连接样式&#xff08;CSS&#xff09;&#xff1a;让元素应用预定义的视觉效果⚙️ 绑定行为&#xff08…...

MySQL的并发事务问题及事务隔离级别

一、并发事务问题 1). 赃读&#xff1a;一个事务读到另外一个事务还没有提交的数据。 比如 B 读取到了 A 未提交的数据。 2). 不可重复读&#xff1a;一个事务先后读取同一条记录&#xff0c;但两次读取的数据不同&#xff0c;称之为不可重复读。 事务 A 两次读取同一条记录&…...

ProfiNet 分布式 IO 在某污水处理厂的应用

随着城市化进程的加速&#xff0c;污水处理厂的规模和复杂性不断增加&#xff0c;对自动化控制系统的要求也越来越高。PROfinet 分布式 IO 作为一种先进的工业通信技术&#xff0c;以其高速、可靠、灵活的特性&#xff0c;为污水处理厂的自动化升级提供了有力支持。本文将结合某…...

vue2使用笔记、vue2和vue3的区别

文章目录 vue2和vue3的区别1. 实现数据响应式的原理不同2. 生命周期不同3. vue 2.0 采用了 option 选项式 API&#xff0c;vue 3.0 采用了 composition 组合式 API4. 新特性编译宏5. 父子组件间双向数据绑定 v-model 不同6. v-for 和 v-if 优先级不同7. 使用的 diff 算法不同8.…...

Vue2数组数字字段求和技巧 数字求和方法

<template><div><p>总和: {{ totalSum }}</p></div> </template><script> export default {data() {return {items: [{ id: 1, value: 10 },{ id: 2, value: 20 },{ id: 3, value: 30 }]};},computed: {totalSum() {return this.ite…...

vue2 , el-select 多选树结构,可重名

人家antd都支持&#xff0c;elementplus 也支持&#xff0c;vue2的没有&#xff0c;很烦。 网上其实可以搜到各种的&#xff0c;不过大部分不支持重名&#xff0c;在删除的时候可能会删错&#xff0c;比如树结构1F的1楼啊&#xff0c;2F的1楼啊这种同时勾选的情况。。 可以全…...

Excel处理控件Aspose.Cells教程:使用 C# 从 Excel 进行邮件合并

邮件合并功能让您能够轻松批量创建个性化文档&#xff0c;例如信函、电子邮件、发票或证书。您可以从模板入手&#xff0c;并使用电子表格中的数据进行填充。Excel 文件中的每一行都会生成一个新文档&#xff0c;并在正确的位置包含正确的详细信息。这是一种自动化重复性任务&a…...

Jenkins | Jenkins构建成功服务进程关闭问题

Jenkins构建成功服务进程关闭问题 1. 原因2. 解决 1. 原因 Jenkins 默认会在构建结束时终止所有由构建任务启动的子进程&#xff0c;即使使用了nohup或后台运行符号&。 2. 解决 在启动脚本中加上 BULID_IDdontkillme #--------------解决jenkins 自动关闭进程问题-----…...

模块化架构下的前端调试体系建设:WebDebugX 与多工具协同的工程实践

随着前端工程化的发展&#xff0c;越来越多的项目采用模块化架构&#xff1a;单页面应用&#xff08;SPA&#xff09;、微前端、组件化框架等。这类架构带来了良好的可维护性和复用性&#xff0c;但也带来了新的调试挑战。 本文结合我们在多个模块化项目中的真实经验&#xff…...

EXCEL通过DAX Studio获取端口号连接PowerBI

EXCEL通过DAX Studio获取端口号连接PowerBI 昨天我分享了EXCEL链接模板是通过获取端口号和数据库来连接PowerBI模型的&#xff0c;链接&#xff1a;浅析EXCEL自动连接PowerBI的模板&#xff0c;而DAX Studio可以获取处于打开状态的PowerBI的端口号。 以一个案例分享如何EXCEL…...

PostgreSQL 技术峰会,为您打造深度交流优质平台

峰会背景 PostgreSQL 作为全球领先的开源关系型数据库管理系统&#xff0c;凭借其强大的功能、高度的扩展性和稳定性&#xff0c;在云计算、大数据、人工智能等领域得到了广泛应用。随着数字化转型的加速&#xff0c;企业对数据库技术的需求日益复杂和多样化&#xff0c;Postg…...