1.前置准备
pip install pyjwt(默认安装最新版)
2.jwt三个部分的介绍
2.1Header
头部包含两部分,一个是token的类型,另一个是加密类型
2.2payload
payload是装载在jwt中的一些有效信息,是可以自定义的一部分,比如我想在验证完这个jwt之后直接取到用户的id,昵称之类的,就可以放在这个地方,怎么取到后面会说
这里放的是wx小程序里main获取的openid和过期时间
2.3signature
这个部分是整个jwt最核心的地方,他需要经过base64url编码的header,payload,以及我们提供的一把密钥,通过header中指定的算法(这里是HS256)算出的一个字符串
得到header,payload和signature后用‘.’连接就得到了jwt
eg:
eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJvcGVuaWQiOiIoJ29RdVdsNVdGeWdscEpVb2tJQ2N5U25PZWJ3TWsnLCkiLCJleHAiOjE3MDkyMTM4NDZ9.2BT5AhrkYB5ww0jetD7qIz9DntXmXbYYdOTHdxMO9Wo
2.4解密原理
1.后端接收到前端传来的token
2.对token进行分割(分成header,payload,signature)
3.对payload进行base64url解密得到payload中的信息
4.将header和payload拼接后进行HS256加密看是否等于base64解密的signature,如果相等则验证成功
3.1代码示例
在根目录下创建文件夹jwt.auth,创建py文件jwt.auth
文件代码如下:
一个用来创建jwt,一个用来验证jwt
import jwt
import datetime
import djangoProject.settings
def create_jwtToken(openid):
expire_time = datetime.datetime.utcnow() + datetime.timedelta(days=7)
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
payload = {
'openid': openid,
"exp": expire_time
}
result = jwt.encode(payload=payload, key=djangoProject.settings.SECRET_KEY, algorithm='HS256', headers=headers)
return result
def identify_token(token):
try:
verified_payload = jwt.decode(token, key=djangoProject.settings.SECRET_KEY, algorithms="HS256")
#验证通过返回payload中的信息
return verified_payload
#不通过返回报错
except jwt.ExpiredSignatureError:
print('token已失效')
return False
except jwt.DecodeError:
print('token认证失败')
return False
except jwt.InvalidTokenError:
print('非法的token')
return False
如果是2.x的python,create_jwtToken里面的result要写成
result = jwt.encode(payload=payload, key=djangoProject.settings.SECRET_KEY, algorithm='HS256', headers=headers).decode("utf-8")
3.x版本都是unicode就不用decode了
调用示例:
打印的结果(openid是隐私信息就用乱码代替了):
eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJvcGVuaWQiOiIoJ29RdVdsNVdGeWdscEpVb2tJQ2N5U25PZWJ3TWsnLCkiLCJleHAiOjE3MDkyNzI2NDJ9.EZRwUn6fF7F5_qwFHxITu04blp6z6jP7L-BbAViCnhY
{'openid': "('dafadfasfsdfafda',)", 'exp': 1709272642}
好了,现在我们已经有了生成jwt和验证jwt的方法,那具体在函数里面该怎么认证呢?
3.2jwt认证方式以及通过中间件添加全局认证
3.2.1单个函数添加认证
def func(request):
#我的前端是以在header中添加参数jwttoken来传递的,所以获取方式如下
jwtToken = request.META['HTTP_JWTTOKEN']
#如果是用url参数的方式传递也可以,用相应的方法获取token就行了
res=jwt_auth.identify_token(jwtToken)
if not res:
return HttpResponse("TOKEN ERROR")
#后面写正常流程即可
#...
正常的话不会有任何反应,如果有问题的话会报错,然后阻断后面的函数执行(报错的方法写在认证那里了)
3.2.2通过中间件添加全局认证
如果只有几个函数还可以挨个添加,但如果有几百个函数呢,我们不可能去每个函数里面都加这几句,这个时候就需要中间件来帮忙了
在根目录下创建软件包middleware,包中创建py文件check_function_middleware
文件代码如下:
from django.http import HttpResponse
from django.urls import resolve
from django.utils.deprecation import MiddlewareMixin
from jwt_auth import jwt_auth
class CheckFunctionMiddleware(MiddlewareMixin):
#如果所有的视图函数都要检验token,那login界面也会无法触发,所以有部分函数是可以不需要验证token的
#把这些函数的名字写在排除表中即可
#如果函数是 def func(request):,在表中写func即可
EXCLUDED_FUNCTIONS = ['login', 'getJwtToken', 'getToken']
#这个函数在所有视图函数之前被触发,用来检验token的合法性刚好
def process_request(self, request):
jwtToken = request.META['HTTP_JWTTOKEN']
#获取函数的名称
path = request.path
match = resolve(path)
request_name = match.func.__name__
#如果不在排除表中则触发
if request_name not in self.EXCLUDED_FUNCTIONS:
print("this func is not in the middleware dict")
res=jwt_auth.identify_token(jwtToken)
#检验不通过则返回错误
if not res:
return HttpResponse("TOKEN ERROR")
接下来只要全局注册一下中间件就行了
在setting.py中(路径写成CheckFunctionMiddleware类的路径就行):
至此,基本功能已经完成。