第十篇:DRF之实现JWT认证

第十篇:DRF之实现JWT认证

目录

一、JWT的构成

在用户注册或登录之后,我们想要记录用户的登录状态,或者为用户创建身份认证的凭证,我们不在使用Session认证机制,而是使用Json Web Token(本质就是token)认证机制。

JWT(Json Web Token)就是一段字符串,由三段信息构成的,将这三段信息文本用.连接在一起就构成了JWT字符串。类似于如下。

"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjI3Mjk2ODc4LCJlbWFpbCI6IiJ9.dR5BTVVTGKmMxYCktBqLOqNZrl2sgf_htm_sgsrlPqA"

第一部分我们成为头部(header),第二部分称其为载荷(payload),第三部分是签发(signature)。

二、JWT认证图

第十篇:DRF之实现JWT认证

三、JWT工作原理

  1. jwt分三段式:头.体.签名 (header.payload.signature)。

  2. 头和体使用base64进行可逆转码(不是加密,以为可以反解),让服务器可以反解出user对象,而签名是不可逆加密,从而保证整个token的安全性。

  3. 头体签名三部分,都是采用json格式的字符串,进行加密,可逆转码使用base64算法,不可以加密使用md5算法。

  4. 头中的内容是基本信息:公司信息、项目组信息、token采用的加密方式信息。

    {
        "company": "公司信息",
        ...
    }
    
  5. 体中的内容是关键信息:用户主键、用户名、签发时客户端信息(设备号、地址)、过期时间【每次登录请求发来的token都不一样,因为过期时间不同】.

    {
    	"user_id": 1,
    	...
    }
    
  6. 签名中的内容是安全信息:头的转码结果 + 体的转码结果 + 服务器不对外公开的安全密钥,将其全部进行md5加密。

    {
    	"head": "头的转码字符串",
    	"payload": "体的转码字符串",
    	"secret_key": "安全密钥"
    }
    

四、JWT校验流程

我们需要将客户端发来的token数据进行校验,来验证用户的身份。具体步骤如下。

  1. 将token按照.拆分成三段字符串,第一段是头加密字符串,我们一般不需要做任何处理。
  2. 第二段是体加密字符串,我们需要反接出用户主键,通过主键从User表中就能得到登录用户。而过期时间和设备信息都属于安全信息,是为了确保token没过期,和来自同一设备的。
  3. 再将 第一段 + 第二段 + 服务器安全密钥,使用md5进行不可逆加密,与得到的第三段签名字符串进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户。

五、DRF项目中实现jwt认证

"""步骤"""
1、用账号密码访问登录接口,登录接口逻辑中调用签发token的算法,得到token
   返回给客户端,客户端自己存到cookies中。
2、校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,
   所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,
   在视图类中用request.user就能访问登录的用户。

"""补充"""
登录接口不能做 认证和权限校验,必须进行局部禁用。

1、安装djangorestframework-jwt第三方应用。

pip3 install djangorestframework-jwt

2、创建一个项目,模型表中的用户表,继承AbstractUser,重写auth_user表。

"""settings.py"""
# 配置AUTH_USER_MODEL
AUTH_USER_MODEL = 'app.userinfo'

3、创建超级用户。

username: admin
password: admin123

4、简单使用。

"""urls.py"""
# jwt相关
from rest_framework_jwt.views import ObtainJSONWebToken, VerifyJSONWebToken, RefreshJSONWebToken, obtain_jwt_token

urlpatterns = [
    # jwt相关
    url(r'^login/', obtain_jwt_token),
    # 登录之后测试其他视图类
    url(r'^test/', views.Test.as_view())
]
  • 全局配置
"""settings.py"""
# 全局配置jwt认证
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        # 'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
    ]
}
  • 局部配置
# 测试视图类
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class Test(APIView):
    authentication_classes = [JSONWebTokenAuthentication]
    ...

自定义实现jwt认证

"""auth.py"""
from rest_framework_jwt.authentication import BaseAuthentication, BaseJSONWebTokenAuthentication
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework import exceptions

class MyToken(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        # 拿到get请求在请求头中的AUTHORIZATION键对应的token值
        jwt_value = str(request.META.get('HTTP_AUTHORIZATION'))
        print(jwt_value)  # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjI3Mjk5MzUzLCJlbWFpbCI6IiJ9.hBnpxweihHhaNWSrwjCvpbJx2YDpiAS2pzUhX0teD9o
        # 认证
        try:
            # 将token值的第二段转化成一个用户信息【没有密码】
            payload = jwt_decode_handler(jwt_value)
            print(payload)  # {'user_id': 1, 'username': 'admin', 'exp': 1627299353, 'email': ''}

        except Exception:
            raise exceptions.AuthenticationFailed("认证失败")
        # 根据payload得到用户对象
        user = self.authenticate_credentials(payload)
        print(user)  # admin 用户对象
        # 将用户对象返回
        return user, None
"""views.py"""
from app.auth import MyToken

# 测试视图类
class Test(APIView):
    authentication_classes = [MyToken]
    # 如何进行token认证
    def get(self, request):
        print(request.user)  # admin 拿到用户对象
        print(type(request.user))  # <class 'app.models.UserInfo'>
        return Response('经过token校验,才能显示。')

最终效果如下所示。
我们访问登录路由。

第十篇:DRF之实现JWT认证

然后我们访问测试路由,用来验证jwt认证是否生效。

第十篇:DRF之实现JWT认证

如果输入错误token,则验证失败,效果如下。

第十篇:DRF之实现JWT认证

上一篇:ROWID伪列


下一篇:漫谈进程和线程