我有一个菜单,用户可以根据自己的权限看到不同的菜单项。我在登录时检查用户是否有该选项,将其存储在全局变量中,并在呈现菜单时检查该变量。
在生产中,菜单只有大约 50% 的时间能正确显示。有时设置了值,有时为空。为什么它不能正常工作?
@app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'POST': user = User.get(request.form['username']) if user.user is None: return redirect('/login/') if user and check_password_hash(user.user.password, request.form['password']): login_user(user) if isinstance(current_user.user, UserTypeOne): group = UserGroup.query.filter_by(id=int(current_user.user.group)).first() app.jinja_env.globals['group_access_to_feature_one'] = group.group_access_to_feature_one return redirect(request.args.get('next') or url_for('index')) return redirect(url_for('login'))
模板header有一个条件来检查该值:
header
{% if group_access_to_feature_one%}<ul>...</ul>{%endif%}
在调试的时候,我把{{ group_access_to_feature_one }}值放进去看,有时候是有True,有时候是空的。
{{ group_access_to_feature_one }}
True
根据您的描述,问题出现在 app.jinja_env.globals['group_access_to_feature_one'] 有时被正确设置为 True,有时为空。这个问题可能与以下几个因素相关:
app.jinja_env.globals['group_access_to_feature_one']
会话管理问题: 您在 login() 路由中设置了 group_access_to_feature_one,但是这个值是设置在全局 Jinja 环境中 (app.jinja_env.globals) 的。如果页面在不同的请求周期中被访问(例如刷新页面、跳转等),并且没有正确传递这个值,您就会遇到该值丢失或不一致的情况。
login()
group_access_to_feature_one
app.jinja_env.globals
group_access_to_feature_one 值的生命周期问题: app.jinja_env.globals 中的全局变量并不会自动与每个用户的会话(session)关联。如果不同的用户登录,可能存在多个会话之间的干扰,或者在某些情况下,用户的 group_access_to_feature_one 被设置为空。
权限设置不一致: 另外一个潜在问题是 current_user 的权限信息可能在某些请求周期中不可用,导致 group_access_to_feature_one 没有被正确设置。
current_user
session
为了避免全局变量可能带来的问题,可以使用 session 来存储用户的权限信息,确保每个用户有自己的独立会话数据。
from flask import session @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'POST': user = User.get(request.form['username']) if user.user is None: return redirect('/login/') if user and check_password_hash(user.user.password, request.form['password']): login_user(user) if isinstance(current_user.user, UserTypeOne): group = UserGroup.query.filter_by(id=int(current_user.user.group)).first() session['group_access_to_feature_one'] = group.group_access_to_feature_one return redirect(request.args.get('next') or url_for('index')) return redirect(url_for('login'))
然后在模板中,您可以通过 session 获取该值:
{% if session['group_access_to_feature_one'] %} <ul>...</ul> {% endif %}
另一种方法是在渲染页面时,直接将该权限信息作为上下文变量传递给模板,而不是使用全局变量。这样确保每次请求都有正确的数据。
@app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'POST': user = User.get(request.form['username']) if user.user is None: return redirect('/login/') if user and check_password_hash(user.user.password, request.form['password']): login_user(user) group_access_to_feature_one = False if isinstance(current_user.user, UserTypeOne): group = UserGroup.query.filter_by(id=int(current_user.user.group)).first() group_access_to_feature_one = group.group_access_to_feature_one return render_template('index.html', group_access_to_feature_one=group_access_to_feature_one) return redirect(url_for('login'))
然后在模板中访问这个变量:
{% if group_access_to_feature_one %} <ul>...</ul> {% endif %}
有时候可能是 group_access_to_feature_one 没有被正确赋值。检查 group.group_access_to_feature_one 是否在 group 对象中确实存在,并且赋值逻辑是正确的。
group.group_access_to_feature_one
group
总结一下:最稳妥的方式是使用 session 来存储每个用户的权限信息,或者确保在渲染模板时直接传递正确的权限信息。这样可以避免因为全局变量或状态不一致导致的权限检查问题。