为Authorization编写CherryPy装饰器

6 投票
2 回答
3727 浏览
提问于 2025-04-16 01:39

我有一个使用cherrypy的应用程序,在某些页面上,我想只允许特定的用户查看这些页面,其他人则需要被引导到一个需要授权的页面。

有没有办法通过自定义装饰器来实现这个功能?我觉得这样做会是最优雅的选择。

下面是我想要实现的一个基本示例:

class MyApp:
    @authorization_required
    def view_page1(self,appID):
        ... do some stuff ...
        return html

def authorization_required(func):
    #what do I put here?

另外,当调用authorization_required这个函数作为装饰器时,能否接受像allow_group1、allow_group2这样的参数?还是说我需要为每个组创建一个单独的装饰器?

2 个回答

15

你其实不想为CherryPy写自定义装饰器。相反,你应该写一个新的工具:

def myauth(allowed_groups=None, debug=False):
    # Do your auth here...
    authlib.auth(...)
cherrypy.tools.myauth = cherrypy.Tool("on_start_resource", myauth)

想了解更多,可以看看这个链接:http://docs.cherrypy.org/en/latest/extend.html#tools。使用工具相比于写自定义装饰器有几个好处:

  1. 你可以直接从工具中获得装饰器,比如:@cherrypy.tools.myauth(allowed_groups=['me']),而且它已经知道怎么处理和同一个函数的cherrypy.exposed不冲突。
  2. 你可以根据需要在不同的地方使用工具,比如针对每个处理器(用装饰器)、针对每个控制器树(通过_cp_config)或者针对每个URI树(在配置文件或字典中)。你甚至可以把它们混合使用,先通过装饰器提供基本功能,然后在配置文件中覆盖它们的行为。
  3. 如果配置文件把你的功能关掉了,你就不用担心调用装饰器函数的性能损失,因为它根本不会被调用。
  4. 你会记得像所有内置工具那样添加一个'debug'参数。;)
  5. 你的功能可以在比自定义装饰器更早(或更晚,如果你需要的话)的时候运行,因为你可以选择不同的“时机”。
  6. 如果需要的话,你的功能可以在多个钩子点运行。
4

好的,在这种情况下,你的装饰器大概会是这样的:

# without any parameters
def authentication_required(f):
    @functools.wraps(f)
    def _authentication_required(*args, **kwargs):
        # Do you login stuff here
        return f(*args, **kwargs)
    return _authentication_required

# With parameters
def authentication_required(*allowed_groups):
    def _authentication_required(f):
        @functools.wraps(f)
        def __authentication_required(*args, **kwargs):
            # Do you login stuff here
            return f(*args, **kwargs)
        return __authentication_required
    return _authentication_required

撰写回答