Flask-Login使用示例

发布于:2025-06-02 ⋅ 阅读:(34) ⋅ 点赞:(0)

项目结构

首先创建以下文件结构:

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

在这里插入图片描述

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

在这里插入图片描述

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

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

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

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到