用于GAE网络服务安全检查的Python装饰器

0 投票
2 回答
1185 浏览
提问于 2025-04-15 14:43

在这篇文章中,Nick 提出了一个装饰器的建议:

Python/WebApp Google App Engine - 测试请求头中的用户名和密码

我正在编写一个 API,准备把几十个方法作为网络服务提供出来,所以这个装饰器听起来是个不错的主意。

我尝试根据这个示例开始编写代码: http://groups.google.com/group/google-appengine/browse_thread/thread/ac51cc32196d62f8/aa6ccd47f217cb9a?lnk=gst&q=timeout#aa6ccd47f217cb9a

我需要它与 Python 2.5 兼容,以便在 Google App Engine (GAE) 上运行。

这是我的尝试。请告诉我我是不是在正确的方向上。 目前在这一行出现了“无效语法”的错误: class WSTest(webapp.RequestHandler):

我的想法是将一个角色数组传递给装饰器。这些角色是我数据库中唯一可以访问每个不同网络服务的角色。

def BasicAuthentication(roles=[]):
  def _decorator(func):
    def _wrapper(*args, **kwds): 
        logging.info("\n\n BasicAuthentication:START:__call__ \n\n") 
        auth = None 
        if 'Authorization' in self.request.headers: 
           auth = self.request.headers['Authorization']
        if not auth:
           self.response.headers['WWW-Authenticate'] = 'Basic realm="MYREALM"'
           self.response.set_status(401)
           self.response.out.write("Authorization required")
           logging.info ("\n\n  Authorization required \n\n") 
           return 

        (username, password) = base64.b64decode(auth.split(' ')[1]).split(':')
        logging.info ("\n\n username = " + username + "  password=" + password + "\n\n")         

        isValidUserPass = False 
        usersSimulatedRole = "Admin" 
        #check against database here...  
        if user == "test12" and password == "test34":
           isValidUserPass = True  
        isValidRole = False 
        if usersSimulatedRole in roles:
           isValidRole = True 
        #next check that user has one of the roles 
        #  TODO 

        if not isValidUserPass:
           self.response.set_status(403)
           self.response.out.write("Forbidden: Userid/password combination failed")

        logging.info("\n\n BasicAuthentication:END:__call__ \n\n") 
        return func(*args, **kwds) 
    return _wrapper
  return _decorator 


@BasicAuthentication(["Admin","Worker"])   #list of roles that can run this function 
class WSTest(webapp.RequestHandler):
  def get(self):
     logging.info("\n\n\n WSTest \n\n") 
     ...etc...

谢谢, Neal Walters

2 个回答

2

类装饰器是在 Python 2.6 版本中新增的功能。

如果你使用的是 2.5 版本,你需要手动包装这个类,或者想其他办法来解决这个问题。那不如试着为 get 方法写一个装饰器呢?

2

你需要写一个方法装饰器,而不是类装饰器:正如lost-theory所说,Python 2.5中没有类装饰器,而且即使有也不太好用,因为RequestHandler类在构造后才会用请求数据进行初始化。使用方法装饰器可以让你有更多的控制权,比如你可以允许GET请求不需要认证,但对POST请求却要求认证。

除此之外,你的装饰器看起来没问题,只需要把它应用到相关的方法上。我唯一建议的改变是把.set_status()的调用换成.error()的调用,并且去掉response.write的调用;这样你就可以在RequestHandler类中重写.error(),为每种可能的状态码输出一个漂亮的错误页面。

撰写回答