tornado后端session用户认证鉴权解决方案
tornado框架自身没有集成session鉴权,但是对cookie支持良好。由于现在前端vue部署在一个端口上,后端tornado分布式应用部署在多个端口上,这就会导致浏览器的跨域问题产生(url不同,即协议,域名,端口三者有不相同的地方)。
在前后端分离的项目中,由于页面的路由跳转由vue控制,后端应用只提供数据。这样就会使鉴权任务变得较为复杂。一个比较良好的解决思路是,在前端需要鉴权才能访问的路由中添加一个后端异步请求,该请求用来判断用户是否登录,这样来判断用户当前是否有权限访问该页面。同时,后端需要 登录才能访问的接口,用修饰器来判断用户当前是否登录。下面提供一种tornado实现session的解决方案。
在新建一个HTTP请求时,需要初始化一个session类,该类应该实现以下功能:
能够从请求头的cookie中得到session_id;
能够生成一个全新的session_id,并将其返回给client;
若server得到的session_id失效,则清空client的cookie;
若server得到的sess_id有效,则从redis中取出对应的用户信息
在一个HTTP请求结束时,需要判断,当前这个链接是否为”登录成功“的API,如果是,则需要将对应的用户信息存储到redis中,并生成一个新的session_id返回给用户。
代码如下:
BaseHandler
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
| class BaseHandler(web.RequestHandler): def initialize(self): self.session_save_tag = False self.session = None
async def prepare(self): await self.init_session() if get_config().session['session_key_name'] in self.session: self.current_user = LoginUser(self.session[get_config().session['session_key_name']]) def on_finish(self): if self.session is not None and self.session_save_tag: get_loop().add_callback(self.session.save) get_logger().info("[一次HTTP请求结束]") async def init_session(self): if not self.session: self.session = Session(self) await self.session.init_fetch() def save_session(self): self.session_save_tag = True self.session.generate_session_id() get_logger().info("【登录】生成session_id结束")
def save_login_user(self, user: dict): login_user = LoginUser(None) login_user['username'] = user.get("username", "") login_user['email'] = user.get("email", "") login_user['phone'] = user.get("phone", "") self.session[get_config().session['session_key_name']] = login_user self.current_user = login_user self.save_session()
|
login API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class LoginHandler(BaseHandler): async def post(self): try: username = self.data['username'] password = self.data['password'] doc_user = await get_one_data(self.mongodb_manager, Config.mongodb_config['user_info'], {'username': username}) print(doc_user) if doc_user is not None and password == doc_user['password']: self.save_login_user(doc_user) get_logger().info("登录成功,用户信息已经保存") except Exception as e: error = traceback.format_exc() get_logger().error("login fail[{}]:{}".format(e, error))
|