首页 > 解决方案 > 无法让 @login_required 装饰器工作

问题描述

我无法让我的应用程序接受登录用户。我没有收到错误,并且还没有实现密码的逻辑。我正在按照readthedocs中的步骤操作,但无法解决。

预期: 用户登录并访问需要登录的页面。

实际: 用户登录但在尝试访问需要登录的页面时被重定向到登录页面。

我的代码中遗漏了什么?

编辑:我的load_user(user_id)方法总是不返回,这是为什么呢?

EDIT2:我开始意识到我的用户对象只在登录方法中创建。我必须在代码中进行哪些更改才能使用户可以通过其他方法访问?

    from flask import Flask, render_template, request, redirect, session
    from flask_login import LoginManager, login_required, login_user, UserMixin, logout_user
    from werkzeug.security import generate_password_hash
    
    
    app = Flask(__name__)
    
    app.secret_key = "Redacted"
    login_manager = LoginManager()
    login_manager.init_app(app)
    
    
    class User:
        def __init__(self, name):
            self.name = name
    
        def is_authenticated(self):
            return True
    
        def is_active(self):
            return True
    
        def is_anonymous(self):
            return False
    
        def get_id(self):
            return unicode(1)
    
    
    @login_manager.user_loader
    def load_user(user_id):
        try:
            return User.get_id(user_id)
        except:
            return None
    
    
    login_manager.login_view = 'login'
    
    
    @app.route('/')
    @login_required
    def index():
        return render_template('index.html')
    
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == "POST":
            name = request.form.get("username")
            password = generate_password_hash(request.form.get("password"))
            if not name:
                print("debug: did not recieve a name")
            user = User(name)
            login_user(user)
            return redirect('/')
        else:
            return render_template('login.html')
    
    
    @app.route('/logout', methods=['GET'])
    @login_required
    def logout():
        logout_user()
        return redirect('/')
    
    
    if __name__ == '__main__':
        app.run(debug=True, host='0.0.0.0')

标签: pythonflask

解决方案


文档和您的代码之间存在一些差异。

你的代码:

return User.get_id(user_id)

不返回用户实例,而是返回 ID。你也可能有其他错误。然后,如果出现异常,则返回 None:

    except:
        return None

但否则异常会被忽视,这不是一件好事。我建议您至少在开发模式下提出异常,或者至少在某处记录消息。如果忽略发生的异常,这只会使程序更难调试。

我个人使用类似的东西:

if current_user.is_authenticated:
    return redirect(url_for('index'))

form = LoginForm()

if form.validate_on_submit():
    user = User.query.filter_by(username=form.username.data).first()
    if user is None or not user.check_password(form.password.data):
        errors.append('Invalid username or password')
        # log failure
        return redirect(url_for('cp_bp.login'))
    else:
        login_user(user)

这个想法是通过名称(使用 ORM FlaskAlchemy)定位用户,然后检查密码,然后登录用户。

您可能知道,但您的代码尚未完成。您正在登录用户而不检查密码是否正确。

当您在 Flask 中有一个有效会话时,您可以使用current_user来引用登录用户。

你像这样导入它(连同其他需要的方法):

from flask_login import LoginManager, login_required, current_user, login_user, logout_user

然后,您可以根据您对 User 模型的个人实现,在代码中使用类似:current_user.name或其他地方的属性。current_user.id


推荐阅读