Skip to content

Instantly share code, notes, and snippets.

@kelleyk
Created July 9, 2011 15:51
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kelleyk/1073682 to your computer and use it in GitHub Desktop.
Save kelleyk/1073682 to your computer and use it in GitHub Desktop.
A simple decorator that makes a RequestHandler prompt for basic auth username and password
# A decorator that lets you require HTTP basic authentication from visitors.
# Kevin Kelley <kelleyk@kelleyk.net> 2011
# Use however makes you happy, but if it breaks, you get to keep both pieces.
# Post with explanation, commentary, etc.:
# http://kelleyk.com/post/7362319243/easy-basic-http-authentication-with-tornado
# Usage example:
#@require_basic_auth
#class MainHandler(tornado.web.RequestHandler):
# def get(self, basicauth_user, basicauth_pass):
# self.write('Hi there, {0}! Your password is {1}.' \
# .format(basicauth_user, basicauth_pass))
# def post(self, **kwargs):
# basicauth_user = kwargs['basicauth_user']
# basicauth_pass = kwargs['basicauth_pass']
# self.write('Hi there, {0}! Your password is {1}.' \
# .format(basicauth_user, basicauth_pass))
def require_basic_auth(handler_class):
def wrap_execute(handler_execute):
def require_basic_auth(handler, kwargs):
auth_header = handler.request.headers.get('Authorization')
if auth_header is None or not auth_header.startswith('Basic '):
handler.set_status(401)
handler.set_header('WWW-Authenticate', 'Basic realm=Restricted')
handler._transforms = []
handler.finish()
return False
auth_decoded = base64.decodestring(auth_header[6:])
kwargs['basicauth_user'], kwargs['basicauth_pass'] = auth_decoded.split(':', 2)
return True
def _execute(self, transforms, *args, **kwargs):
if not require_basic_auth(self, kwargs):
return False
return handler_execute(self, transforms, *args, **kwargs)
return _execute
handler_class._execute = wrap_execute(handler_class._execute)
return handler_class
@wingyiu
Copy link

wingyiu commented Mar 30, 2015

got an exception in tornado 4.1 py3

[E 150330 13:26:22 http1connection:53] Uncaught exception
    Traceback (most recent call last):
      File "/Users/user/venv/py3/lib/python3.4/site-packages/tornado/http1connection.py", line 236, in _read_message
        delegate.finish()
      File "/Users/user/venv/py3/lib/python3.4/site-packages/tornado/httpserver.py", line 269, in finish
        self.delegate.finish()
      File "/Users/user/venv/py3/lib/python3.4/site-packages/tornado/web.py", line 1898, in finish
        self.execute()
      File "/Users/user/venv/py3/lib/python3.4/site-packages/tornado/web.py", line 1930, in execute
        f.add_done_callback(lambda f: f.exception())
    AttributeError: 'bool' object has no attribute 'add_done_callback'

@alexandrevicenzi
Copy link

Try this:

# -*- coding: utf-8 -*-

import base64

def basic_auth(auth_func=lambda *args, **kwargs: True, after_login_func=lambda *args, **kwargs: None, realm='Restricted'):
    def basic_auth_decorator(handler_class):
        def wrap_execute(handler_execute):
            def require_basic_auth(handler, kwargs):
                def create_auth_header():
                    handler.set_status(401)
                    handler.set_header('WWW-Authenticate', 'Basic realm=%s' % realm)
                    handler._transforms = []
                    handler.finish()

                auth_header = handler.request.headers.get('Authorization')

                if auth_header is None or not auth_header.startswith('Basic '):
                    create_auth_header()
                else:
                    auth_decoded = base64.decodestring(auth_header[6:])
                    user, pwd = auth_decoded.split(':', 2)

                    if auth_func(user, pwd):
                        after_login_func(handler, kwargs, user, pwd)
                    else:
                        create_auth_header()

            def _execute(self, transforms, *args, **kwargs):
                require_basic_auth(self, kwargs)
                return handler_execute(self, transforms, *args, **kwargs)

            return _execute

        handler_class._execute = wrap_execute(handler_class._execute)
        return handler_class
    return basic_auth_decorator

Usage:

def check_credentials(user, pwd):
    return user == 'foo'

@basic_auth(check_credentials)
class MyHandler(tornado.web.RequestHandler):
    pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment