You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Peewee的Flask登录页面搭建及login_user验证故障排查

问题分析与解决方案

看起来你遇到的核心问题集中在登录逻辑错误、Flask-Login的用户加载逻辑不对,以及密码验证方式错误上,咱们一步步拆解修复:

1. 先修正User模型与UserManager.py的核心问题

首先你的User模型里,password字段设置了unique=True完全没必要——不同用户的密码哈希可能出现重复(虽然概率极低,但这不是合理的约束),还会导致创建用户失败。另外,get_password函数逻辑完全错误,它试图用明文密码去匹配数据库里的哈希密码找用户,这根本不是验证密码的正确方式;还有提前调用db.close()会导致后续请求无法访问数据库,因为Peewee的连接关闭后需要重新初始化。

修正后的UserManager.py:

from peewee import *
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin

db = SqliteDatabase('C:/path/to/Users.db')

class User(Model, UserMixin):
    username = CharField(unique=True)
    # 移除password的unique约束
    password = CharField()
    
    class Meta:
        database = db

# 初始化表(建议放在App启动时执行,或者用Flask-Peewee扩展管理)
db.connect()
db.create_tables([User], safe=True)

def create_user(username, password):
    try:
        User.create(
            username=username,
            password=generate_password_hash(password))
    except IntegrityError:
        print("User already exists")

def delete_user(user_id):
    try:
        user = User.get(User.username == user_id)
        user.delete_instance()
        print(f"{user_id} deleted")
    except User.DoesNotExist:
        print('no such user')

def list_users():
    try:
        print('Users: ')
        for person in User.select():
            print(person.username)
    except Exception as e:
        print(f'Error listing users: {e}')

def remake_user(username, password):
    delete_user(username)
    create_user(username, password)
    print(f'{username} remade')

# 根据用户名获取用户对象,找不到返回None
def get_user_by_username(username):
    try:
        return User.get(User.username == username)
    except User.DoesNotExist:
        return None

# 不需要get_password函数,密码验证直接用check_password_hash

2. 修复Flask-Login的user_loader与登录逻辑

你的load_user函数犯了个关键错误:Flask-Login传递给它的参数是用户的ID(整数),不是用户名,所以必须根据ID查找用户。另外,登录逻辑里的username == get_username(username)完全不成立——get_username返回的是User对象,不是字符串;密码验证也不能直接对比明文和哈希值,必须用check_password_hash来验证。

修正后的app.py:

from flask import *
from UserManager import *
from flask_login import LoginManager, login_required, login_user, logout_user, current_user

# Host config
host = "127.0.0.1"
port = 8000

# App config
app = Flask(__name__)
login_manager = LoginManager()
login_manager.init_app(app)
# 指定登录页面,未登录访问受保护页面时会跳转过来
login_manager.login_view = 'login_page'
app.secret_key = 'dev'

# 添加请求钩子管理数据库连接,确保每个请求都有可用连接
@app.before_request
def before_request():
    db.connect()

@app.after_request
def after_request(response):
    db.close()
    return response

# Routing
@app.route('/')
def hello():
    return redirect(url_for('login_page'))

# 修正user_loader:根据用户ID加载用户
@login_manager.user_loader
def load_user(user_id):
    try:
        return User.get_by_id(int(user_id))
    except User.DoesNotExist:
        return None

@app.route('/login', methods=['GET', 'POST'])
def login_page():
    error = None
    if request.method == 'POST':
        username = request.form['username'].strip()
        password = request.form['password'].strip()
        
        # 先根据用户名获取用户对象
        user = get_user_by_username(username)
        # 验证用户存在且密码匹配
        if user and check_password_hash(user.password, password):
            # 执行登录,可添加remember=True参数实现记住登录
            login_user(user)
            # 跳转至受保护页面
            return redirect(url_for('index'))
        else:
            error = 'Invalid Credentials. Please try again.'
    return render_template('login.html', error=error)

@app.route('/logout')
@login_required
def logout_page():
    logout_user()
    return "Logged Out"

@app.route('/index')
@login_required
def index():
    return f"Authenticated as {current_user.username}"

# Run
if __name__ == "__main__":
    print(' * Testing Server', flush=True)
    app.run(host=host, port=port, debug=True)

3. 优化登录模板(可选)

给模板加上错误信息显示,让用户更直观看到问题:

<html>
<head>
<title>login page</title>
</head>
<body>
<div class="container">
<h1>Please login</h1>
<br>
<!-- 显示错误提示 -->
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<form action="" method="post">
<input type="text" placeholder="Username" name="username" value="{{ request.form.username }}">
<input type="password" placeholder="Password" name="password">
<input type="submit" value="Login">
</form>
</div>
</body>
</html>

关键错误总结

  • 登录逻辑完全错误:直接对比User对象和字符串、明文密码和哈希密码,导致login_user从未被正确触发,所以页面无跳转、也没授权。
  • user_loader逻辑错误:用用户名而非用户ID查找用户,导致Flask-Login无法识别已登录用户,@login_required自然不生效。
  • 数据库连接管理错误:提前关闭数据库连接,导致后续请求无法读取用户数据。
  • User模型约束错误:给password字段加unique约束,可能导致创建用户失败。

按照上述修正后,你应该能正常完成登录跳转,@login_required也会正确拦截未登录的请求。

内容的提问来源于stack exchange,提问作者Isaiah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:22:35