Reputation: 6780
I want to drop GET/POST requests if a token field is not provided in the headers.
Currently I use this code (from GitHub Gist):
def require_basic_auth(handler_class):
def wrap_execute(handler_execute):
def serve_error(handler, status):
handler._transforms = [] # necessary
handler.set_status(status)
handler.finish()
def _execute(self, transforms, *args, **kwargs):
expected_header = self.request.headers.get('X-User-Auth')
if expected_header is None:
return serve_error(self, 403)
kwargs['token'] = expected_header
# Token validation is done in the `post(self, token)` method
return handler_execute(self, transforms, *args, **kwargs)
return _execute
handler_class._execute = wrap_execute(handler_class._execute)
return handler_class
Two problems:
_method
, and I'm a bit uncomfortable manipulating methods whose names begin with a _
AttributeError: '_NullFuture' object has no attribute 'add_done_callback'
Reading a bit, I see that the .prepare()
method might be the best way to implement this. But I haven't found any examples on how to do this properly in .prepare()
.
Can someone show me an example on how to do this?
I forgot to add: The decorator above also conveniently extracted the header into a token
kwarg to be consumed by the post(self, token)
method. I'm not sure how to do that if using prepare(self)
.
Upvotes: 0
Views: 360
Reputation: 21734
Yeah, directly patching Tornado's RequestHandler
is not ideal.
With Tornado, you're supposed to create a base class for your handlers. This base class acts like a "middleware" as seen in other frameworks (Django, Flask, etc.)
Another pattern with Tornado is to create "mixin" classes which is useful for plugging in common features to specific handlers.
This is what I do in my projects:
class BaseHandler(web.RequestHandler):
def prepare(self):
expected_header = self.request.headers.get('X-User-Auth')
if not expected_header:
return self.send_error(401)
# ... other common logic to run before other methods ...
# Inherit your handlers from BaseHandler everywhere
class MyHandler(BaseHandler):
def get(self):
pass
Upvotes: 2