【问题标题】:How to check function decorators in Python如何在 Python 中检查函数装饰器
【发布时间】:2015-05-27 23:39:26
【问题描述】:

我正在使用(真棒)Flask framework 构建一个网站,其中一些路由受到 flask-login @login_required 装饰器的保护,如下所示:

@app.route('/awesomepage')
@login_required  # <-- this is what I mean
def awesome_page():
    return render_template('awesome.html')

当有人注销时,他通常会被重定向到他按下注销时正在查看的页面。但是,当一个人从需要登录的页面(即具有@login_required 装饰器的页面)注销时,他在注销后会收到 401 Unauthorized 错误。因此,当将用户重定向回原始页面时,我想检查他们来自的页面是否有 @login_required 装饰器,如果有,则将他们重定向到首页。

我当前的注销视图如下所示:

@app.route('/logout')
def logout():
    logout_user()
    next_url = request.args.get('next') or request.referrer or url_for('index')
    return redirect(next_url)

所以在这段代码中,我想检查request.referrer 是否有@login_required 装饰器。有人知道我该怎么做吗?欢迎所有提示!

【问题讨论】:

  • 你不能通过setting a login view 绕过这个问题,让用户被重定向到那里而不是抛出 401 吗?
  • 如果 所有 装饰方法都在一个类中,您可以查找它们的行号以查找它们的第一行代码,如果它们被装饰,则该代码会发生变化,但这很奇怪做事的方式:) 基本上你可以保留一个与装饰器函数代码的第一行号相对应的行号字典,然后使用它来将函数“映射”到它们的装饰器。

标签: python flask decorator python-decorators flask-login


【解决方案1】:

你不能,不容易。

更好的选择是通过在模板中显式设置login_required 标志来告诉页面在注销链接中包含更好的next 值:

@app.route('/awesomepage')
@login_required
def awesome_page():
    return render_template('awesome.html', login_required=True)

并使用以下命令呈现注销链接:

{% if login_required %}{{ url_for('logout', next=url_for('index')) }}
{% else %}{{ url_for('logout' }}{% endif %}

另一种方法是定义一个登录视图,并让login_required 重定向到该视图。那可能是你的索引页。

替代方法是创建一个增强的login_required 装饰器,设置一个全局变量,然后测试:

from functools import wraps

from flask import g
from flask_login import login_required

def my_login_required(f):
    @login_required
    @wraps(f)
    def wrapped(*args, **kwargs):
        g.login_required = True
        return f(*args, **kwargs)
    return wrapped

然后在您的视图上使用该装饰器而不是 Flask-Login 版本:

@app.route('/awesomepage')
@my_login_required
def awesome_page():
    return render_template('awesome.html')

并更新模板以查找全局:

{% if g.login_required %}{{ url_for('logout', next=url_for('index')) }}
{% else %}{{ url_for('logout' }}{% endif %}

【讨论】:

  • 嗯,好主意,但由于重复,这为错误留下了空间。如果我然后更改删除或添加@login_required,我总是必须记住更改render_template 中的login_required=True。没有其他方法可以以某种方式自动化吗?
  • @kramer65:我为您添加了自定义装饰器选项。
  • 太棒了!彻底解决了整个问题。谢谢一百万!
猜你喜欢
  • 2013-02-24
  • 2019-10-05
  • 2018-01-12
  • 2019-12-05
  • 2021-04-14
  • 2023-02-08
  • 2011-07-26
  • 1970-01-01
  • 2016-08-21
相关资源
最近更新 更多