1、JWT的构成
JWT就是一段字符串,由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。示例·
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
# 第一部分我们称其为头部(header),
-说明类型,这里是jwt,声明加密算法,有的会在头里加入公司信息...(最后使用base64转码)
{
'typ': 'JWT',
'alg': 'HS256'
}
# 第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),
- 当前用户的信息(用户名,id,这个token的过期时间,手机号),最后使用base64转码
{
"sub": "1234567898",
"name": "egon",
"admin": true,
"userid":1,
'mobile':123444444
}
# 第三部分是签证(signature).
-把前面两部分的内容通过加密算法+密钥加密后得到的一个字符串
2、JWT认证原理:
-用户携带用户名,密码登录我的系统,校验通过,生成一个token(三部分),返回给用户---》登录功能完成
-访问需要登录的接口(用户中心),必须携带token过来,后端拿到token后,把header和payload截出来,再通过一样的加密方式和密码得到一个signature,和该token的signature比较,如果一样,表示是正常的token,就可以继续往后访问
二、base64介绍及使用
#1、任何语言都有base64的加码和解码,转码方式(加密方式)
#2、python中base64的加密与解密
import base64
import json
dic_info={
"name": "lqz",
"age": 18
}
# 转成json格式字符串
dic_str=json.dumps(dic_info)
print(dic_str)
# 需要用bytes格式
# 加密
base64_str=base64.b64encode(dic_str.encode('utf-8'))
print(base64_str)
# 解密
res_bytes=base64.b64decode('eyJuYW1lIjogImxxeiIsICJhZ2UiOiAxOH0=')
print(res_bytes)
三、jwt基本使用
jwt是内置的,控制用户登录后/未登录的访问
#1、drf中使用jwt,借助第三方
- https://github.com/jpadilla/django-rest-framework-jwt
#2、模块的安装:
- pip3 install djangorestframework-jwt
#3、快速使用(默认使用auth的user表)
1 在默认auth的user表中创建一个用户
2 在路由中配置
path('login/', obtain_jwt_token),
3 用postman向这个地址发送post请求,携带用户名,密码,登陆成功就会返回token
4 obtain_jwt_token本质也是一个视图类,继承了APIView
-通过前端传入的用户名密码,校验用户,如果校验通过,生成token,返回
-如果校验失败,返回错误信息
#4、用户登录以后才能访问某个接口
-jwt模块内置了认证类,拿过来局部配置就可以
-代码示例:
class OrderView(APIView):
# 只配它不行,不管是否登录,都能范围,需要搭配一个内置权限类
authentication_classes = [JSONWebTokenAuthentication, ]
permission_classes = [IsAuthenticated,]
def get(self, request):
print(request.user.username)
return Response('订单的数据')
#5、用户未登录,不能访问
-class OrderView(APIView):
# 只配它不行,不管是否登录,都能范围,需要搭配一个内置权限类
authentication_classes = [JSONWebTokenAuthentication, ]
def get(self, request):
print(request.user.username)
return Response('订单的数据')
#6、如果用户携带了token,并且配置了JSONWebTokenAuthentication,从request.user就能拿到当前登录用户,如果没有携带,当前登录用户就是匿名用户
#7、前端要发送请求,携带jwt,格式必须如下
-把token放到请求头中,key为:Authorization
-value必须为:jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo1LCJ1c2VybmFtZSI6ImVnb24xIiwiZXhwIjoxNjA1MjQxMDQzLCJlbWFpbCI6IiJ9.7Y3PQM0imuSBc8CUe_h-Oj-2stdyzXb_U-TEw-F82WE
四、控制登录接口返回的数据格式
#1、控制登录接口返回的数据格式如下
{
code:100
msg:登录成功
token:asdfasfd
username:egon
}
#2、写一个函数
from homework.serializer import UserReadOnlyModelSerializer
def jwt_response_payload_handler(token, user=None, request=None):
return {'code': 100,
'msg': '登录成功',
'token': token,
'user': UserReadOnlyModelSerializer(instance=user).data
}
#3、在setting.py中配置
import datetime
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER': 'homework.utils.jwt_response_payload_handler',
}
五、自定义基于jwt的认证类
1、自己实现基于jwt的认证类,通过认证,才能继续访问,通不过认证就返回错误
2、代码示例:
class JwtAuthentication(BaseJSONWebTokenAuthentication):
def authenticate(self, request):
# 认证逻辑()
# token信息可以放在请求头中,请求地址中
# key值可以随意
# token=request.GET.get('token')
token=request.META.get('HTTP_Authorization'.upper())
# 校验token是否合法
try:
payload = jwt_decode_handler(token)
except jwt.ExpiredSignature:
raise AuthenticationFailed('过期了')
except jwt.DecodeError:
raise AuthenticationFailed('解码错误')
except jwt.InvalidTokenError:
raise AuthenticationFailed('不合法的token')
user=self.authenticate_credentials(payload)
return (user, token)
3、在视图类中配置
authentication_classes = [JwtAuthentication, ]