Json Web Token
是解决现在前后端分离权限验证的方法之一。
先看几篇参考文章:
在使用session
机制的时候,session
的本质是在服务器中生成的一段随机字符串,在Tornado
的单体应用中我们可以使用set_cookie
和set_secure_cookie
通过浏览器将session
保存到浏览器的cookie
中。因为这个步操作是交给浏览器做的,因此前后端分离的情况的时候,这两个方法就是没用的了。不过,我们可以通过接口将session
返回给前端,前端下次查询接口带上session
也是可以完成前后端分离,我们在后端可以拦截session
获取到保存到session
中的信息。例如使用itsdangerous来进行加密。
JWT
的本质是加密技术,我们在服务器加密生成字符串返回给客户端,客户端保存,下次查询的之后携带上来,服务端进行校验。相比于sesssion
保存在服务器,JWT
是不用保存的。
下面我们看如何在Tornado
中集成JWT
,我们以慕课网实战课程为例。
我们使用的模块是pyjwt
生成加密字符串
# 构建 json web token
# 设置过期时间要设置 UTC 时间 因为内部检查使用的也是 UTC 时间
payload = {
"id": user.id,
"nick_name": user.nick_name,
"exp": datetime.utcnow()
}
token = jwt.encode(payload, self.settings["secret_key"], algorithm='HS256')
re_data["token"] = token
我们将用户的id
和nick_name
设置在payload
中。
那把这个加密字符串返回给前端之后 怎么使用呢?这就是要我们重新抒写权限装饰器然后使用这个token
了。
下面是我们要改写的装饰器。
def authenticated_async(method):
@functools.wraps(method)
async def wrapper(self, *args, **kwargs):
tsessionid = self.request.headers.get("tsessionid", None)
if tsessionid:
# 对token过期进行异常捕捉
try:
# 从 token 中获得我们之前存进 payload 的用户id
send_data = jwt.decode(tsessionid, self.settings["secret_key"], leeway=self.settings["jwt_expire"],
options={"verify_exp": True})
user_id = send_data["id"]
# 从数据库中获取到user并设置给_current_user
try:
user = await self.application.objects.get(User, id=user_id)
self._current_user = user
# 此处需要使用协程方式执行 因为需要装饰的是一个协程
await method(self, *args, **kwargs)
except User.DoesNotExist as e:
self.set_status(401)
except jwt.ExpiredSignatureError as e:
self.set_status(401)
else:
self.set_status(401)
self.finish({})
return wrapper
上面展示了如何使用我们的jwt
。
在需要权限的地方使用了权限装饰器即可。
class GroupHandler(RedisHandler):
@authenticated_async
async def get(self, *args, **kwargs):
总体使用感觉在Flask
中集成itsdangerous
库很类似。