一、jwt介绍和构成
1. 介绍
jwt:Json Web Token,Web方向的Token认证方案
在用户注册或登录之后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证(token串)。我们不再使用session认证机制,而使用Json Web Token(本质就是token)认证机制。
Json Web Token:JWT用在我们前后端做登录认证,如果登录了,就携带token过来,如果没登录,就不携带了,后端通过验证token的准确性,确定是谁访问我们。
2. 构成
JWT就是一段字符串,由三段信息构成的,将这三段信息文本用 .连
接一起就构成了Jwt字符串。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature)。
2.1 头(header)
一般放公司信息,加密方式(没放秘钥)
jwt的头部承载两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法 通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON
2.2 荷载(payload)
一般存放:当前用户信息:用户名,用户id,token过期时间
2.3 签名(signature)
签名由头(base64加密后)和荷载(base64加密后),在通过加密得到的字符串。
二、 jwt签发与认证
以后使用jwt,最核心的就是写两个地方
- 签发(登录接口)
- 登录接口,登录成功,签发token(三段式)
- header,用base64编码,
- payload,用base64编码,
- signature,使用加密方式:用md5把header和payload加密,生成签名,然后再用base64编码
-认证(认证类)
-用户携带token过来,认证
-取出第一部分header
-取出第二部分 payload
-使用之前同样的加密算法(密码),得到新前面
-跟token的第三部分比较,如果一样,表示没有被窜改,顺利继续往下走,返回两个值
-如果被篡改了,抛异常
drf项目的jwt认证开发流程(重点)
""" 1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中 2)校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,在视图类中用request.user就能访问登录的用户 注:登录接口需要做 认证 + 权限 两个局部禁用 """
补充:base64编码
1. base64编码的作用(使用场景):
1. token串使用base64编码
2. 互联网中前后端数据交互,可以使用base64编码
3. 图片二进制可以使用base64编码传递
2. base64 的编码和解码(字符串):是对字符串进行操作,要将字符串转成bytes类型
编码:
解码:
三、drf-jwt使用
可以自己写,也可以使用第三方的
-django-rest-framework-jwt:有点老
-djangorestframework-simplejwt:新的-自己写:https://gitee.com/liuqingzheng/rbac_manager/blob/master/libs/lqz_jwt/token.py
下载:pip install djangorestframework-jwt
1.django-rest-framework-jwt快速使用
签发:默认使用auth的user表签发,登录接口不需要自己写,人家帮我们写了
在总路由文件中进行配置,
from rest_framwork_jwt.views import obtain_jwt_token #这个就是登录接口
urlpatterns = [path('login/', obtain_jwt_token),]
认证:实际上就是认证类
视图类上,配置认证类和权限类
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated]
2. 定制签发返回格式
我们可以自定义返回结果,
1.先写一个函数:
def jwt_response_payload_handler(token, user=None, request=None): return { 'status': 100, 'msg': '登录成功', 'token': token, 'username': user.username }
2. 在配置文件中配置
源码分析
为什么路由这样配置了,就会有个登录接口?
path('login/', obtain_jwt_token)
obtain_jwt_token的本质:ObtainJsonWebToken.as_view()
ObtainJSONWebToken源码:
class ObtainJSONWebToken(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer
# 向login发送post请求,ObtainJSONWebToken一定有个post方法
# 在父类中:JSONWebTokenAPIView post
-登录走的是JSONWebTokenAPIView的post,签发token 是在序列化类中
-签发完token执行了,咱们写的jwt_response_payload_handler,所以才能定制返回格式