基于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
相关产品推荐
相关产品推荐

