File: main.py

package info (click to toggle)
python-tornado 6.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 3,176 kB
  • sloc: python: 28,920; javascript: 156; sh: 100; ansic: 72; xml: 49; makefile: 49; sql: 23
file content (114 lines) | stat: -rw-r--r-- 3,991 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
"""Demo app for GoogleOAuth2Mixin

Recommended usage:
- Register an app with Google following the instructions at
  https://www.tornadoweb.org/en/stable/auth.html#tornado.auth.GoogleOAuth2Mixin
- Use "http://localhost:8888/auth/google" as the redirect URI.
- Create a file in this directory called main.cfg, containing two lines (python syntax):
    google_oauth_key="..."
    google_oauth_secret="..."
- Run this file with `python main.py --config_file=main.cfg`
- Visit "http://localhost:8888" in your browser.
"""

import asyncio
import json
import tornado
import urllib.parse

from tornado.options import define, options
from tornado.web import url

define("port", default=8888, help="run on the given port", type=int)
define("google_oauth_key", help="Google OAuth Key")
define("google_oauth_secret", help="Google OAuth Secret")
define(
    "config_file",
    help="tornado config file",
    callback=lambda path: tornado.options.parse_config_file(path, final=False),
)


class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        user_cookie = self.get_signed_cookie("googledemo_user")
        if user_cookie:
            return json.loads(user_cookie)
        return None


class IndexHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
    @tornado.web.authenticated
    async def get(self):
        try:
            # This is redundant: we got the userinfo in the login handler.
            # But this demonstrates the usage of oauth2_request outside of
            # the login flow, and getting anything more than userinfo
            # leads to more approval prompts and complexity.
            user_info = await self.oauth2_request(
                "https://www.googleapis.com/oauth2/v1/userinfo",
                access_token=self.current_user["access_token"],
            )
        except tornado.httpclient.HTTPClientError as e:
            print(e.response.body)
            raise
        self.write(f"Hello {user_info['name']}")


class LoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
    async def get(self):
        redirect_uri = urllib.parse.urljoin(
            self.application.settings["redirect_base_uri"],
            self.reverse_url("google_oauth"),
        )
        if self.get_argument("code", False):
            access = await self.get_authenticated_user(
                redirect_uri=redirect_uri, code=self.get_argument("code")
            )
            user = await self.oauth2_request(
                "https://www.googleapis.com/oauth2/v1/userinfo",
                access_token=access["access_token"],
            )
            # Save the user and access token.
            user_cookie = dict(id=user["id"], access_token=access["access_token"])
            self.set_signed_cookie("googledemo_user", json.dumps(user_cookie))
            self.redirect("/")
        else:
            self.authorize_redirect(
                redirect_uri=redirect_uri,
                client_id=self.get_google_oauth_settings()["key"],
                scope=["profile", "email"],
                response_type="code",
                extra_params={"approval_prompt": "auto"},
            )


class LogoutHandler(BaseHandler):
    def get(self):
        self.clear_cookie("user")
        self.redirect("/")


async def main():
    tornado.options.parse_command_line()
    app = tornado.web.Application(
        [
            url(r"/", IndexHandler),
            url(r"/auth/google", LoginHandler, name="google_oauth"),
            url(r"/logout", LogoutHandler),
        ],
        redirect_base_uri=f"http://localhost:{options.port}",
        google_oauth=dict(
            key=options.google_oauth_key, secret=options.google_oauth_secret
        ),
        debug=True,
        cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
        login_url="/auth/google",
    )
    app.listen(options.port)
    shutdown_event = asyncio.Event()
    await shutdown_event.wait()


if __name__ == "__main__":
    asyncio.run(main())