🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### Navigation - [index](# "General Index") - [modules](# "Python Module Index") | - [next](# "Running and deploying") | - [previous](# "Templates and UI") | - [Tornado 4.4.dev1 documentation](#) » - [User's guide](#) » # Authentication and security ### Cookies and secure cookies You can set cookies in the user's browser with the `set_cookie`method: ~~~ class MainHandler(tornado.web.RequestHandler): def get(self): if not self.get_cookie("mycookie"): self.set_cookie("mycookie", "myvalue") self.write("Your cookie was not set yet!") else: self.write("Your cookie was set!") ~~~ Cookies are not secure and can easily be modified by clients. If youneed to set cookies to, e.g., identify the currently logged in user,you need to sign your cookies to prevent forgery. Tornado supportssigned cookies with the [`set_secure_cookie`](# "tornado.web.RequestHandler.set_secure_cookie") and[`get_secure_cookie`](# "tornado.web.RequestHandler.get_secure_cookie") methods. To use these methods,you need to specify a secret key named `cookie_secret` when youcreate your application. You can pass in application settings askeyword arguments to your application: ~~~ application = tornado.web.Application([ (r"/", MainHandler), ], cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__") ~~~ Signed cookies contain the encoded value of the cookie in addition to atimestamp and an [HMAC](http://en.wikipedia.org/wiki/HMAC) [http://en.wikipedia.org/wiki/HMAC] signature.If the cookie is old or if the signature doesn't match,`get_secure_cookie` will return `None` just as if the cookie isn'tset. The secure version of the example above: ~~~ class MainHandler(tornado.web.RequestHandler): def get(self): if not self.get_secure_cookie("mycookie"): self.set_secure_cookie("mycookie", "myvalue") self.write("Your cookie was not set yet!") else: self.write("Your cookie was set!") ~~~ Tornado's secure cookies guarantee integrity but not confidentiality.That is, the cookie cannot be modified but its contents can be seen by theuser. The `cookie_secret` is a symmetric key and must be kept secret –anyone who obtains the value of this key could produce their own signedcookies. By default, Tornado's secure cookies expire after 30 days. To change this,use the `expires_days` keyword argument to `set_secure_cookie`*and* the`max_age_days` argument to `get_secure_cookie`. These two values arepassed separately so that you may e.g. have a cookie that is valid for 30 daysfor most purposes, but for certain sensitive actions (such as changing billinginformation) you use a smaller `max_age_days` when reading the cookie. Tornado also supports multiple signing keys to enable signing keyrotation. `cookie_secret` then must be a dict with integer key versionsas keys and the corresponding secrets as values. The currently usedsigning key must then be set as `key_version` application settingbut all other keys in the dict are allowed for cookie signature validation,if the correct key version is set in the cookie.To implement cookie updates, the current signing key version can bequeried via [`get_secure_cookie_key_version`](# "tornado.web.RequestHandler.get_secure_cookie_key_version"). ### User authentication The currently authenticated user is available in every request handleras [`self.current_user`](# "tornado.web.RequestHandler.current_user"), and in everytemplate as `current_user`. By default, `current_user` is`None`. To implement user authentication in your application, you need tooverride the `get_current_user()` method in your request handlers todetermine the current user based on, e.g., the value of a cookie. Hereis an example that lets users log into the application simply byspecifying a nickname, which is then saved in a cookie: ~~~ 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("Hello, " + name) class LoginHandler(BaseHandler): def get(self): self.write('<html><body><form action="/login" method="post">' 'Name: <input type="text" name="name">' '<input type="submit" value="Sign in">' '</form></body></html>') def post(self): self.set_secure_cookie("user", self.get_argument("name")) self.redirect("/") application = tornado.web.Application([ (r"/", MainHandler), (r"/login", LoginHandler), ], cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__") ~~~ You can require that the user be logged in using the [Pythondecorator](http://www.python.org/dev/peps/pep-0318/) [http://www.python.org/dev/peps/pep-0318/][`tornado.web.authenticated`](# "tornado.web.authenticated"). If a request goes to a method with thisdecorator, and the user is not logged in, they will be redirected to`login_url` (another application setting). The example above could berewritten: ~~~ class MainHandler(BaseHandler): @tornado.web.authenticated def get(self): name = tornado.escape.xhtml_escape(self.current_user) self.write("Hello, " + name) settings = { "cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__", "login_url": "/login", } application = tornado.web.Application([ (r"/", MainHandler), (r"/login", LoginHandler), ], **settings) ~~~ If you decorate `post()` methods with the `authenticated`decorator, and the user is not logged in, the server will send a`403` response. The `@authenticated` decorator is simplyshorthand for `if not self.current_user: self.redirect()` and maynot be appropriate for non-browser-based login schemes. Check out the [Tornado Blog example application](https://github.com/tornadoweb/tornado/tree/stable/demos/blog) [https://github.com/tornadoweb/tornado/tree/stable/demos/blog] for acomplete example that uses authentication (and stores user data in aMySQL database). ### Third party authentication The [`tornado.auth`](# "tornado.auth") module implements the authentication andauthorization protocols for a number of the most popular sites on theweb, including Google/Gmail, Facebook, Twitter, and FriendFeed.The module includes methods to log users in via these sites and, whereapplicable, methods to authorize access to the service so you can, e.g.,download a user's address book or publish a Twitter message on theirbehalf. Here is an example handler that uses Google for authentication, savingthe Google credentials in a cookie for later access: ~~~ class GoogleOAuth2LoginHandler(tornado.web.RequestHandler, tornado.auth.GoogleOAuth2Mixin): @tornado.gen.coroutine def get(self): if self.get_argument('code', False): user = yield self.get_authenticated_user( redirect_uri='http://your.site.com/auth/google', code=self.get_argument('code')) # Save the user with e.g. set_secure_cookie else: yield self.authorize_redirect( redirect_uri='http://your.site.com/auth/google', client_id=self.settings['google_oauth']['key'], scope=['profile', 'email'], response_type='code', extra_params={'approval_prompt': 'auto'}) ~~~ See the [`tornado.auth`](# "tornado.auth") module documentation for more details. ### Cross-site request forgery protection [Cross-site requestforgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery) [http://en.wikipedia.org/wiki/Cross-site_request_forgery], orXSRF, is a common problem for personalized web applications. See the[Wikipediaarticle](http://en.wikipedia.org/wiki/Cross-site_request_forgery) [http://en.wikipedia.org/wiki/Cross-site_request_forgery] formore information on how XSRF works. The generally accepted solution to prevent XSRF is to cookie every userwith an unpredictable value and include that value as an additionalargument with every form submission on your site. If the cookie and thevalue in the form submission do not match, then the request is likelyforged. Tornado comes with built-in XSRF protection. To include it in your site,include the application setting `xsrf_cookies`: ~~~ settings = { "cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__", "login_url": "/login", "xsrf_cookies": True, } application = tornado.web.Application([ (r"/", MainHandler), (r"/login", LoginHandler), ], **settings) ~~~ If `xsrf_cookies` is set, the Tornado web application will set the`_xsrf` cookie for all users and reject all `POST`, `PUT`, and`DELETE` requests that do not contain a correct `_xsrf` value. Ifyou turn this setting on, you need to instrument all forms that submitvia `POST` to contain this field. You can do this with the special[`UIModule`](# "tornado.web.UIModule")`xsrf_form_html()`, available in all templates: ~~~ <form action="/new_message" method="post"> {% module xsrf_form_html() %} <input type="text" name="message"/> <input type="submit" value="Post"/> </form> ~~~ If you submit AJAX `POST` requests, you will also need to instrumentyour JavaScript to include the `_xsrf` value with each request. Thisis the [jQuery](http://jquery.com/) [http://jquery.com/] function we use at FriendFeed forAJAX `POST` requests that automatically adds the `_xsrf` value toall requests: ~~~ function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } jQuery.postJSON = function(url, args, callback) { args._xsrf = getCookie("_xsrf"); $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST", success: function(response) { callback(eval("(" + response + ")")); }}); }; ~~~ For `PUT` and `DELETE` requests (as well as `POST` requests thatdo not use form-encoded arguments), the XSRF token may also be passedvia an HTTP header named `X-XSRFToken`. The XSRF cookie is normallyset when `xsrf_form_html` is used, but in a pure-Javascript applicationthat does not use any regular forms you may need to access`self.xsrf_token` manually (just reading the property is enough toset the cookie as a side effect). If you need to customize XSRF behavior on a per-handler basis, you canoverride [`RequestHandler.check_xsrf_cookie()`](# "tornado.web.RequestHandler.check_xsrf_cookie"). For example, if youhave an API whose authentication does not use cookies, you may want todisable XSRF protection by making `check_xsrf_cookie()` do nothing.However, if you support both cookie and non-cookie-based authentication,it is important that XSRF protection be used whenever the currentrequest is authenticated with a cookie. © Copyright 2009-2016, The Tornado Authors. Created using [Sphinx](http://sphinx-doc.org/) 1.3.5.