问题描述
我目前正在建立我自己的第一个项目,这是一个使用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')