Python Cron作业无法访问带有admin_必需装饰符的url
根据文档,应允许Cron作业访问受管理保护的视图。但是,如果在get方法上有Python Cron作业无法访问带有admin_必需装饰符的url,python,unit-testing,google-app-engine,flask,cron,Python,Unit Testing,Google App Engine,Flask,Cron,根据文档,应允许Cron作业访问受管理保护的视图。但是,如果在get方法上有@admin\u required装饰程序,则会出现302错误 在应用程序yaml中,我定义了: - url: /generator script: run.news.app login: admin 视图: class GeneratorView(MethodView): @admin_required def get(self): return 'success', 200
@admin\u required
装饰程序,则会出现302错误
在应用程序yaml中,我定义了:
- url: /generator
script: run.news.app
login: admin
视图:
class GeneratorView(MethodView):
@admin_required
def get(self):
return 'success', 200
cron:
- description: Scrape every 3 hours
url: /generator
schedule: every 3 hours synchronized
def admin_required(func):
"""Requires App Engine admin credentials"""
@wraps(func)
def decorated_view(*args, **kwargs):
if users.get_current_user():
if not users.is_current_user_admin():
abort(401) # Unauthorized
return func(*args, **kwargs)
return redirect(users.create_login_url(request.url))
return decorated_view
url.py
app.add_url_rule('/generator', 'generator', view_func=GeneratorView.as_view('generator'))
cron作业:
class GeneratorView(MethodView):
@admin_required
def get(self):
return 'success', 200
cron:
- description: Scrape every 3 hours
url: /generator
schedule: every 3 hours synchronized
def admin_required(func):
"""Requires App Engine admin credentials"""
@wraps(func)
def decorated_view(*args, **kwargs):
if users.get_current_user():
if not users.is_current_user_admin():
abort(401) # Unauthorized
return func(*args, **kwargs)
return redirect(users.create_login_url(request.url))
return decorated_view
装饰师:
class GeneratorView(MethodView):
@admin_required
def get(self):
return 'success', 200
cron:
- description: Scrape every 3 hours
url: /generator
schedule: every 3 hours synchronized
def admin_required(func):
"""Requires App Engine admin credentials"""
@wraps(func)
def decorated_view(*args, **kwargs):
if users.get_current_user():
if not users.is_current_user_admin():
abort(401) # Unauthorized
return func(*args, **kwargs)
return redirect(users.create_login_url(request.url))
return decorated_view
有趣的是,当我删除admin\u required
decorator时,由于app.yaml中的login:admin
,url仍然只受admin保护
但是,由于缺少decorator,我的单元测试没有通过授权检查
def test_generator_fails_as_normal_user(self):
self.setCurrentUser(u'john@example.com', u'123')
rv = self.client.get('/generator')
self.assertEqual(rv.status_code, 401)
断言错误:200!=401
如果我把装饰器放回去,单元测试通过,cron作业失败。有什么建议吗?单元测试的
self.client.get
无疑不会返回到app.yaml
进行路由选择——因此,如果您删除在decorator中执行的应用程序级别检查,它会允许非管理员用户通过也就不足为奇了
然而,真正的问题是,当cron
点击该URL时,装饰程序没有发现任何人“登录”。这是在以下位置暗示的(当然应该更清楚/明确地记录!):
注意:虽然cron作业可以使用受登录:admin限制的URL路径,但是,
他们不能使用受登录:必需限制的URL路径
这表明服务基础结构不会通过检查当前登录的用户来验证cron请求,因为它不会发现任何请求。相反,它依赖于请求中的头:
来自Cron服务的请求还将包含HTTP头:
X-AppEngine-Cron:true
X-AppEngine-Cron
头由Google App Engine在内部设置。如果
您的请求处理程序找到此标头,它可以信任该请求
是一个cron请求。如果标头存在于外部用户中
请求您的应用程序时,它将被剥离,但来自已登录应用程序的请求除外
在应用程序的管理员中,允许谁设置
标题用于测试目的
因此,您的装饰程序必须检查self.request
——如果发现X-AppEngine-Cron:true
,它必须让请求通过,否则它可以继续执行您现在正在执行的检查
我不太确定在您选择的web框架中如何最好地获取请求的标题,您没有提到,但如果它是例如webapp2
,则类似于:
@wraps(func)
def decorated_view(self, *args, **kwargs):
if self.request.headers.get('X-AppEngine-Cron') == 'true':
return func(self, *args, **kwargs)
# continue here with the other checks you do now
应该做到这一点。似乎在说你不能像这样装饰你的方法:
装饰视图
因为视图类本身不是视图
添加到路由系统中的功能它没有多大用处
装饰班级本身的意义。相反,你要么
手动装饰as_view()的返回值:
从烧瓶0.8开始,还有另一种方法可以
指定要在类声明中应用的装饰器列表:
class UserAPI(MethodView):
decorators = [user_required]
由于来电者的隐式自我,您无法使用
但是,在视图的各个方法上使用常规视图装饰器,
记住这一点。
不过,我不明白其中的道理 谢谢你的全面回复。我正在使用烧瓶
。我希望这个片段在那里也能起作用。我要试一试。感谢if request.headers.get('X-AppEngine-Cron')=='true':return func(*args,**kwargs)
在Flask中工作。非常感谢