Asynchronous login tornado

Viewed 482

I used Tornado to create a login page which works on synchronous method.Now I want to make it asynchronous. So what are the changes I should do to the following code:

import tornado.ioloop
import tornado.web
import http
import time

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        return self.get_secure_cookie("user")

class MainHandler(BaseHandler):
    def get(self):
        if not self.current_user:
            self.redirect("/login")
            return
        name = tornado.escape.xhtml_escape(self.current_user)
        self.write('<html>'
    '<head> '
    '<title>WELCOME  </title>'
    '</head>'
    '<body style="background:orange;"'

    '<div align="center">'
    '<div style="margin-top:200px;margin-bottom:10px;">'
    '<span style="width:500px;color:black;font-size:30px;font-weight:bold;">WELCOME </span>'
    '</div>'
    '<div style="margin-bottom:5px;">'"Hello, " + name)

class LoginHandler(BaseHandler):
    def get(self):
        self.write('<html><body><form action="/login" method="post">'
                   '<div><span style="width:100px;;height: 500px;color:black;font-size:60;font-weight:bold;">'
                   'LOGIN'
                   '<div><span style="width:100px;;height: 500px;color:purple;font-size:30;font-weight:bold;">'
                   'NAME <input type="text" name="name">'
                   '<div><span style="width:100px;height: 500px;color:purple;font-size:30;font-weight:bold;">PASSWORD</span><input style="width:150px;" type="password" name="password" id="password" value="">'
                   '</div>'                   
                   '<input type="submit" value="Sign in">'
                   '</form></body></html>')

    def post(self):
        self.set_secure_cookie("user", self.get_argument("name"))
        time.sleep(10)
        self.redirect("/")

application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/login", LoginHandler),
], cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__")

application.listen(5000)
tornado.ioloop.IOLoop.current().start()

In my code I have three classes BaseHandler, MainHandler and LoginHandler. Any help will be appreciated.

3 Answers

A simple example

Python 3.5 introduced the async and await keywords (functions using these keywords are also called “native coroutines”). See the answer for more details.

Every class-based view we construct for our Tornado app must inherit from the RequestHandler object found in tornado.web.

If we override the prepare method, we can set some logic to run that'll do whenever a request is received.

def tornado.web.RequestHandler.get_current_user(self) - Override to determine the current user from, e.g., a cookie.

A subclass may override get_current_user(), which will be called automatically the first time self.current_user is accessed. get_current_user() will only be called once per request, and is cached for future access.

class BaseHandler(tornado.web.RequestHandler):
    def prepare(self):
        if self.get_argument("btn1", None) is not None:
            print("detected click on btn Profile")
            self.redirect("/profile")
            return

        if self.get_argument("btn2", None) is not None:
            print("detected click on btn Sources")
            self.redirect("/sources")
            return

        if self.get_argument("logout", None) is not None:
            self.clear_cookie("username")
            self.redirect("/")
            return

        if self.get_argument("btnSignIn", None) is not None:
            print("detected click on btnSignIn")
            self.redirect("/signin")
            return

    def get_current_user(self):
        a = self.get_secure_cookie("username")
        if a:
            return a.decode("utf-8")
        return None
class LoginHandler(BaseHandler):
    def get(self):
        self.render('login.html')

    def prepare(self):
        super().prepare()

    async def post(self):
        username = self.get_argument("username")
        password = self.get_argument("password")

        my_db = self.settings['db']
        collection = my_db.test

        val = await do_check_one(collection, username, password)

        if val is not None:
            self.set_secure_cookie("username", username)
            self.redirect("/profile")
        else:
            self.write('<h1>Wrong credentials</h1>')

For a better understanding see: Simplest async/await example.

async def do_check_one(my_collection, value1, value2):
    document = await my_collection.find_one({"name": value1, "password": value2})
    return document

and main:

Options must be defined with tornado.options.define before use, generally at the top level of a module. The options are then accessible as attributes of tornado.options.options.

The main() method of your application does not need to be aware of all of the options used throughout your program; they are all automatically loaded when the modules are loaded. However, all modules that define options must have been imported before the command line is parsed.


define("port", default=8000, help="run on the given port", type=int)


if __name__ == '__main__':
    tornado.options.parse_command_line()

    client = motor.motor_tornado.MotorClient('localhost', 27017)
    db = client.test
    collection = db.test

    settings = {
        "template_path": os.path.join(os.path.dirname(__file__), "templates"),
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
        "cookie_secret": "_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
        "login_url": "/login",
        "db": db,
        "debug": True,
        "xsrf_cookies": True
    }

    app = tornado.web.Application(
        handlers=[(r'/', MainHandler),
                  (r'/sources', SourceHandler),
                  (r'/login', LoginHandler),
                  (r'/signin', SigninHandler),
                  (r'/profile', ProfileHandler),
                  (r'/favicon.ico', tornado.web.StaticFileHandler, dict(path=settings['static_path'])),
                  ],
        **settings
    )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    try:
        tornado.ioloop.IOLoop.instance().start()
        print('Server started...')
    except KeyboardInterrupt:
        print('Server has shut down.')

Your main() method can parse the command line or parse a config file with either parse_command_line or parse_config_file:

tornado.options.parse_command_line()
# or
tornado.options.parse_config_file("/etc/server.conf")
Related