tornado后端session用户认证鉴权解决方案

tornado框架自身没有集成session鉴权,但是对cookie支持良好。由于现在前端vue部署在一个端口上,后端tornado分布式应用部署在多个端口上,这就会导致浏览器的跨域问题产生(url不同,即协议,域名,端口三者有不相同的地方)。

在前后端分离的项目中,由于页面的路由跳转由vue控制,后端应用只提供数据。这样就会使鉴权任务变得较为复杂。一个比较良好的解决思路是,在前端需要鉴权才能访问的路由中添加一个后端异步请求,该请求用来判断用户是否登录,这样来判断用户当前是否有权限访问该页面。同时,后端需要 登录才能访问的接口,用修饰器来判断用户当前是否登录。下面提供一种tornado实现session的解决方案。
在新建一个HTTP请求时,需要初始化一个session类,该类应该实现以下功能:

  1. 能够从请求头的cookie中得到session_id;

  2. 能够生成一个全新的session_id,并将其返回给client;

  3. 若server得到的session_id失效,则清空client的cookie;

  4. 若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))