JWT
jwt=Json Web token
1)jwt分三段式:头.体.签名 (head.payload.sgin)
2)头和体是可逆加密,让服务器可以反解出user对象;签名是不可逆加密,保证整个token的安全性的
3)头体签名三部分,都是采用json格式的字符串,进行加密,可逆加密一般采用base64算法,不可逆加密一般采用hash(md5)算法
头中的内容是基本信息:公司信息、项目组信息、token采用的加密方式信息
体中的内容是关键信息:用户主键、用户名、签发时客户端信息(设备号、地址)、过期时间
签名中的内容是安全信息:头的加密结果 + 体的加密结果 + 服务器不对外公开的安全码 进行md5加密
基于jwt校验
将token按 . 拆分为三段字符串:
1)第一段 头加密字符串 一般不需要做任何处理
2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间和设备信息都是安全信息,确保token没过期,且时同一设备来的
3)再用 第一段 + 第二段 + 服务器安全码 不可逆md5加密,与第三段 签名字符串 进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户
drf项目的jwt认证开发流程(重点)
1)登录接口逻辑中签发token,返回给客户端,存到cookies中
2)在认证类中,校验token,所有视图类请求,请求有token,就会反解出user对象,在视图类中用request.user就能访问登录的用户
注:登录接口需要做 认证 + 权限 两个局部禁用
安装pip install djangorestframework-jwt
from rest_framework_jwt.views import ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken,obtain_jwt_token
path('login/', obtain_jwt_token),
jwt的配置参数
import datetime
JWT_AUTH={
'JWT_RESPONSE_PAYLOAD_HANDLER':'app02.utils.my_jwt_response_payload_handler',
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # 过期时间,手动配置
}
控制登录接口返回的数据格式
-第一种方案,自己写登录接口
-第二种写法,用内置,控制登录接口返回的数据格式
-jwt的配置信息中有这个属性
'JWT_RESPONSE_PAYLOAD_HANDLER':'rest_framework_jwt.utils.jwt_response_payload_handler',
-重写jwt_response_payload_handler,配置
def jwt_response_payload_handler(token, user=None, request=None):
return {
'token': token
}
自定义基于jwt的认证
from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.utils import jwt_decode_handler # 跟上面是一个
import jwt
from api import models
class MyJwtAuthentication(BaseAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
try:
payload=jwt_decode_handler(jwt_value)
except Exception as e:
raise AuthenticationFailed(str(e))
# 第一种,去数据库查
user=models.User.objects.get(pk=payload.get('user_id'))
# 第二种不查库
user=models.User(id=payload.get('user_id'),username=payload.get('username'))
return user,jwt_value
raise AuthenticationFailed('您没有携带认证信息')
class MyJwtAuthentication(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
jwt_value=request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
try:
payload=jwt_decode_handler(jwt_value)
except Exception as e:
raise AuthenticationFailed(str(e))
user=self.authenticate_credentials(payload)
return user,jwt_value
raise AuthenticationFailed('您没有携带认证信息')