部分页面只有登陆成功才能容许访问,不然自动跳转到登陆页面html
https://git.oschina.net/donggen/tornado-test.git 分支是 tornado总结5git
1.没有登陆的状况下访问 “http://localhost:8899”, 自动跳转到了 登陆页面web
能够看到地址栏是 http://localhost:8899/login?next=%2Fhomejson
2.输入错误的用户名或密码浏览器
3.输入正确的用户名和密码cookie
弹窗显示登陆成功,而且跳转到了home页面(这个跳转是js作的, 若是是get请求能够使用redirect来进行跳转)。app
跳转后的页面dom
import os import tornado.httpserver import tornado.ioloop import tornado.web import my_uimodules from handlers.home import HomeHandler from handlers.login import LoginHandler class PageNotFoundHandler(tornado.web.RequestHandler): def get(self): return self.write_error(404) class Application(tornado.web.Application): def __init__(self): handlers = [ (r"/", tornado.web.RedirectHandler, {"url": "/home"}), (r"/login", LoginHandler), (r"/home", HomeHandler), (r".*", PageNotFoundHandler), ] settings = dict( static_path= os.path.join(os.path.dirname(__file__), "static"), template_path=os.path.join(os.path.dirname(__file__), "templates"), ui_modules=my_uimodules, cookie_secret='1111111111111111111111111111111111111111111111111', login_url='/login', debug=True ) tornado.web.Application.__init__(self, handlers, **settings) self.user_list = { '1': {'login': 'admin', 'password': '123456', 'name': '管理员'} } if __name__ == "__main__": port = 8899 application = Application() http_server = tornado.httpserver.HTTPServer(application, xheaders=True) http_server.listen(port) print('Listen on http://localhost:{0}'.format(port)) tornado.ioloop.IOLoop.instance().start()
用户列表被定义成一个字典存储在变量self.user_list里面,用户id是key,其余数据是用户相关信息。async
目前只存储了一个用户,用户id是“1”,用户名是“admin”,密码是“123456”,用户昵称是“管理员”。ide
import binascii import tornado.web import os class BaseHandler(tornado.web.RequestHandler): # 类的静态变量用于保存登陆信息, 存储的是token对应的user_id __TOKEN_LIST = {} def __init__(self, application, request, **kwargs): super(BaseHandler, self).__init__(application, request, **kwargs) def new_token(self): while True: new_token = binascii.hexlify(os.urandom(16)).decode("utf8") if new_token not in self.__TOKEN_LIST: return new_token def on_login_success(self, new_token, user_id): self.set_cookie('_token', new_token) self.__TOKEN_LIST[new_token] = user_id def get_current_user(self): # 从cookie中读取token token = self.get_cookie('_token') # 根据token获得绑定的用户id if token and token in self.__TOKEN_LIST: user_id = self.__TOKEN_LIST[token] return self.application.user_list[user_id] # 没有找到就返回none, 表示该用户没有登陆 return None
定义了一个BaseHandler类,该类将会被全部须要登陆才能访问的页面继承
__TOKEN_LIST 这个被定义成类的静态变量,用于存储登陆成功时的_token以及对应的用户id。
on_login_success 是把登陆成功的token放入__TOKEN_LIST。
get_current_user 这个方法是登陆判断的关键,tornado要求登陆判断必须提供这个方法,通常返回 已登陆的用户信息, 若是返回None表示用户没有登陆。 我这边的判断方法是获取当前请求的cookie,判断里面的_token是否在__TOKEN_LIST里面,若是有就返回对应用户的相关信息。
如下代码是 tornado.web.RequestHandler current_user属性的源代码,current_user这个属性是用来进行用户权限验证, 对于这个属性的处理有两种方法,其中一种方法是子类重写get_current_user, 我这里使用的就是这个。
@property def current_user(self): """The authenticated user for this request. This is set in one of two ways: * 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:: def get_current_user(self): user_cookie = self.get_secure_cookie("user") if user_cookie: return json.loads(user_cookie) return None * It may be set as a normal variable, typically from an overridden `prepare()`:: @gen.coroutine def prepare(self): user_id_cookie = self.get_secure_cookie("user_id") if user_id_cookie: self.current_user = yield load_user(user_id_cookie) Note that `prepare()` may be a coroutine while `get_current_user()` may not, so the latter form is necessary if loading the user requires asynchronous operations. The user object may any type of the application's choosing. """ if not hasattr(self, "_current_user"): self._current_user = self.get_current_user() return self._current_user
import tornado.web from handlers import BaseHandler class HomeHandler(BaseHandler): @tornado.web.authenticated def get(self): user_info = self.current_user return self.render('home.html', user_info=user_info)
HomeHandler 的get方法有个装饰器 @tornado.web.authenticated,该装饰器是用来告知tornado处理HomeHandler的get请求时,须要判断用户是否已登陆,若是没有就会跳转到login_url, 若是是post方法机会返回HTTP代码 403。
import json from handlers import BaseHandler class LoginHandler(BaseHandler): def get(self): return self.render('login.html') def post(self): # 从post的body中获取登陆信息 requ_data = json.loads(self.request.body.decode()) login = requ_data['login'] password = requ_data['password'] # 检测用户名和密码 login_user_id = None for user_id in self.application.user_list: if login == self.application.user_list[user_id]['login']: login_user_id = user_id break if not login_user_id: return self.finish('用户名或密码错误') if password != self.application.user_list[login_user_id]['password']: return self.finish('用户名或密码错误') # 一个token对应一个已经登陆的用户 new_token = self.new_token() self.on_login_success(new_token, login_user_id) return self.finish('ok')
前面一大段代码是获取请求里面的用户名和密码,而后进行登陆判断,若是成功就会设置一个 "_token" 的cookie, 而且保存登陆状态,设置cookie这个动做是在 BaseHandler的 on_login_success方法里面完成的。
略,能够去git上面查看。
事实上没有设置current_user属性这个动做, 而是让get_current_user返回登陆成功的值。