处理登录Flask Web应用程序

问题描述

我目前正在建立我自己的第一个项目,这是一个使用Flask与Spotify API交互的Web应用程序。经过在本地和Heroku暂存环境中进行广泛测试后,该项目已准备就绪。但是,我目前遇到一个小的登录错误”,似乎无法绕开我的头脑。

单击“登录”按钮时,应用程序将请求发送到Spotify API,Spotify API将在用户确认读取其数据后发送回授权码。此确认将导致用户重定向到Web应用程序的“ /配置文件路由”。到目前为止,登录过程在不同环境中的流程:

  • 本地过程始终运行顺利(阅读:单击“登录”按钮一次,将用户重定向到/ profile路由)
  • 登台(Heroku):单击登录按钮会向Spotify API生成正确的请求。但是,当第一次单击它时,我被重定向登录页面(由于我的login_required Flask装饰器)。 第二次单击它时,它还会生成正确的请求,并将用户正确地定向到“ /配置文件路径”。

我可以在服务器日志中看到第一次单击“登录”按钮会生成正确的请求。但是好像'/ profile route'的login_required装饰器所进行的验证似乎'太快'了吗?还是与缓存有关?因为我还可以通过删除缓存并强制刷新页面来重现该错误(有时)。

我最近在会话中添加了SECRET_KEY并将SESSION_PERMANENT从False更改为True,但是我不认为这是引起此问题的原因吗?我认为某些代码可能会导致这个小错误

# Ensure responses aren't cached
@app.after_request
def after_request(response):
    response.headers["Cache-Control"] = "no-cache,no-store,must-revalidate"
    response.headers["Expires"] = 0
    response.headers["Pragma"] = "no-cache"
    return response


# Configure session to use filesystem
app.config['SECRET_KEY'] = os.urandom(64)
app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = True
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
def login_required(f):
        """
        Decorate routes to require login:
        http://flask.pocoo.org/docs/1.0/patterns/viewdecorators/
        """
        @wraps(f)
        def decorated_function(*args,**kwargs):
            if session.get("authorization_header") is None:
                return redirect(url_for('login'))
            return f(*args,**kwargs)
        return decorated_function
@app.route("/")
    def index():
        """ Shows landing page """
        if session.get("authorization_header") is not None:
            return redirect(url_for('profile'))
    
        return render_template("index.html")
    
    
    @app.route("/login")
    def login():
        """ Shows login page """
        if session.get("authorization_header") is not None:
            return redirect(url_for('profile'))
    
        return render_template("login.html")
    
    
    @app.route("/logout")
    @helpers.login_required
    def logout():
        """ Logs user out """
        # Forget any user_id
        session.clear()
    
        # Redirect user to login form
        return redirect(url_for("index"))
    
    
    @app.route("/profile")
    @helpers.login_required
    def profile():
       """ Shows overview of user's Spotfy profile """

解决方法

不确定这是否是您的问题,但可能会导致某些奇怪的行为...

app.config['SECRET_KEY'] = os.urandom(64)这将导致在每个heroku dyno上设置不同的秘密密钥(如果运行多个工作程序;对于同步工作程序,默认值为2),因为该随机字符串是在工作程序启动时动态生成的。>

请注意,os.urandom不能用于生成密钥。取而代之的是use the secrets module,并设置结果字符串as a config var in heroku CLI并使用以下命令将其加载到您的应用中:

import os
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')