Flask-Login使用示例

news2025/6/7 4:38:46

项目结构

首先创建以下文件结构:

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_hash

class User(UserMixin):
    def __init__(self, id, username, email, password_hash):
        self.id = id
        self.username = username
        self.email = email
        self.password_hash = password_hash
    
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)
    
    @staticmethod
    def create_password_hash(password):
        return generate_password_hash(password)

# 模拟数据库存储
users_db = {}
next_user_id = 1

def 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 user
    return None

def create_user(username, email, password):
    global next_user_id
    password_hash = User.create_password_hash(password)
    user = User(next_user_id, username, email, password_hash)
    users_db[next_user_id] = user
    next_user_id += 1
    return 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_user

app = 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来控制项目:
在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

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

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

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

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

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

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、新建项目…

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…

【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]区间。 以猫咪预测为例 假设单个样…

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

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

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

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

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…

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

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

C# 委托UI控件更新例子,何时需要使用委托

1. 例子1 private void UdpRxCallBackFunc(UdpDataStruct info) {// 1. 前置检查防止无效调用if (textBoxOutput2.IsDisposed || !textBoxOutput2.IsHandleCreated)return;// 2. 使用正确的委托类型Invoke(new Action(() >{// 3. 双重检查确保安全if (textBoxOutput2.IsDis…

大模型数据流处理实战:Vue+NDJSON的Markdown安全渲染架构

在Vue中使用HTTP流接收大模型NDJSON数据并安全渲染 在构建现代Web应用时&#xff0c;处理大模型返回的流式数据并安全地渲染到页面是一个常见需求。本文将介绍如何在Vue应用中通过普通HTTP流接收NDJSON格式的大模型响应&#xff0c;使用marked、highlight.js和DOMPurify等库进…

python项目如何创建docker环境

这里写自定义目录标题 python项目创建docker环境docker配置国内镜像源构建一个Docker 镜像验证镜像合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPant…

PyTorch--池化层(4)

池化层&#xff08;Pooling Layer&#xff09; 用于降低特征图的空间维度&#xff0c;减少计算量和参数数量&#xff0c;同时保留最重要的特征信息。 池化作用&#xff1a;比如1080p视频——720p 池化层的步长默认是卷积核的大小 ceil 允许有出界部分&#xff1b;floor 不允许…

2025年大模型平台落地实践研究报告|附75页PDF文件下载

本报告旨在为各行业企业在建设落地大模型平台的过程中&#xff0c;提供有效的参考和指引&#xff0c;助力大模型更高效更有价值地规模化落地。本报告系统性梳理了大模型平台的发展背景、历程和现状&#xff0c;结合大模型平台的特点提出了具体的落地策略与路径&#xff0c;同时…

PPTAGENT:让PPT生成更智能

想要掌握如何将大模型的力量发挥到极致吗&#xff1f;叶梓老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具。 1小时实战课程&#xff0c;您将学习到如何轻松上手并有效利用 Llama Factory 来微调您的模型&#xff0c;以发挥其最大潜力。 CSDN教学平台录播地址…

《汇编语言》第13章 int指令

中断信息可以来自 CPU 的内部和外部&#xff0c;当 CPU 的内部有需要处理的事情发生的时候&#xff0c;将产生需要马上处理的中断信息&#xff0c;引发中断过程。在第12章中&#xff0c;我们讲解了中断过程和两种内中断的处理。 这一章中&#xff0c;我们讲解另一种重要的内中断…