在本節中,咱們將創建一個應用,詢問訪客的名字,而後將其存儲在安全cookie中,以便以後取出。後續的請求將認出回客,並展現給她一個定製的頁面。你將學到login_url參數和tornado.web.authenticated裝飾器的相關知識,這將消除在相似應用中常常會涉及到的一些頭疼的問題。html
在這個例子中,咱們將只經過存儲在安全cookie裏的用戶名標識一我的。當某人首次在某個瀏覽器(或cookie過時後)訪問咱們的頁面時,咱們展現一個登陸表單頁面。表單做爲到LoginHandler路由的POST請求被提交。post方法的主體調用set_secure_cookie()來存儲username請求參數中提交的值。python
代碼清單6-2中的Tornado應用展現了咱們本節要討論的驗證函數。LoginHandler類渲染登陸表單並設置cookie,而LogoutHandler類刪除cookie。web
import tornado.httpserver import tornado.ioloop import tornado.web import tornado.options import os.path from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie("username") class LoginHandler(BaseHandler): def get(self): self.render('login.html') def post(self): self.set_secure_cookie("username", self.get_argument("username")) self.redirect("/") class WelcomeHandler(BaseHandler): @tornado.web.authenticated def get(self): self.render('index.html', user=self.current_user) class LogoutHandler(BaseHandler): def get(self): if (self.get_argument("logout", None)): self.clear_cookie("username") self.redirect("/") if __name__ == "__main__": tornado.options.parse_command_line() settings = { "template_path": os.path.join(os.path.dirname(__file__), "templates"), "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", "xsrf_cookies": True, "login_url": "/login" } application = tornado.web.Application([ (r'/', WelcomeHandler), (r'/login', LoginHandler), (r'/logout', LogoutHandler) ], **settings) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
代碼清單6-3和6-4是應用templates/目錄下的文件。數據庫
<html> <head> <title>Please Log In</title> </head> <body> <form action="/login" method="POST"> {% raw xsrf_form_html() %} Username: <input type="text" name="username" /> <input type="submit" value="Log In" /> </form> </body> </html>
<html> <head> <title>Welcome Back!</title> </head> <body> <h1>Welcome back, {{ user }}</h1> </body> </html>
爲了使用Tornado的認證功能,咱們須要對登陸用戶標記具體的處理函數。咱們可使用@tornado.web.authenticated裝飾器完成它。當咱們使用這個裝飾器包裹一個處理方法時,Tornado將確保這個方法的主體只有在合法的用戶被發現時纔會調用。讓咱們看看例子中的WelcomeHandler吧,這個類只對已登陸用戶渲染index.html模板。瀏覽器
class WelcomeHandler(BaseHandler): @tornado.web.authenticated def get(self): self.render('index.html', user=self.current_user)
在get方法被調用以前,authenticated裝飾器確保current_usr屬性有值。(咱們將簡短的討論這個屬性。)若是current_user值爲假(None、False、0、""),任何GET或HEAD請求都將把訪客重定向到應用設置中login_url指定的URL。此外,非法用戶的POST請求將返回一個帶有403(Forbidden)狀態的HTTP響應。安全
若是發現了一個合法的用戶,Tornado將如期調用處理方法。爲了實現完整功能,authenticated裝飾器依賴於current_user屬性和login_url設置,咱們將在下面看到具體講解。cookie
請求處理類有一個current_user屬性(一樣也在處理程序渲染的任何模板中可用)能夠用來存儲爲當前請求進行用戶驗證的標識。其默認值爲None。爲了authenticated裝飾器可以成功標識一個已認證用戶,你必須覆寫請求處理程序中默認的get_current_user()方法來返回當前用戶。app
實際的實現由你決定,不過在這個例子中,咱們只是從安全cookie中取出訪客的姓名。很明顯,你但願使用一個更加魯棒的技術,可是出於演示的目的,咱們將使用下面的方法:函數
class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie("username")
儘管這裏討論的例子並無在存儲和取出用戶密碼或其餘憑證上有所深刻,但本章中討論的技術能夠以最小的額外努力來擴展到查詢數據庫中的認證。tornado
讓咱們簡單看看應用的構造函數。記住這裏咱們傳遞了一個新的設置給應用:login_url是應用登陸表單的地址。若是get_current_user方法返回了一個假值,帶有authenticated裝飾器的處理程序將重定向瀏覽器的URL以便登陸。
settings = { "template_path": os.path.join(os.path.dirname(__file__), "templates"), "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", "xsrf_cookies": True, "login_url": "/login" } application = tornado.web.Application([ (r'/', WelcomeHandler), (r'/login', LoginHandler), (r'/logout', LogoutHandler) ], **settings)
當Tornado構建重定向URL時,它還會給查詢字符串添加一個next參數,其中包含了發起重定向到登陸頁面的URL資源地址。你可使用像self.redirect(self.get_argument('next', '/'))這樣的行來重定向登陸後用戶回到的頁面。