drf之jwt使用

发布时间 2023-09-21 19:26:09作者: 树苗叶子

简介

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT构成

第一部分我们称它为头部(header);
第二部分我们称其为载荷(payload, 类似于飞机上承载的物品);
第三部分是签证(signature).

JWT的使用

安装

  • djangorestframework-jwt

快速使用

定制程度低,但使用起来方便,什么都不需要自己配置。
此方法只能限制使用django的auth表

  1. 添加路由
    urls.py
from rest_framework_jwt.views import obtain_jwt_token
# 添加如下路由
path('login/', obtain_jwt_token),
  1. 创建登录用户
python38 manage.py createsuperuser
  1. 使用postman发送请求
    请求地址:http://127.0.0.1:8000/login/
    请求类型:POST
    请求数据:

如下图:
image

总结:可以看到,我们只是配置了一个路由,就会自动生成了一个登录接口,会返回一个token字符串。但此方法一般不太适合在生产中使用,因为返回的信息不符合标准。

定制返回格式

  1. 创建一个函数
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'code': 100,
        'msg': '登录成功',
        'token': token,
        'username': user.username
    }
  1. 在settings.py中添加配置
JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.mytoken.jwt_response_payload_handler',
}
  1. 使用postman发送请求
    image

jwt认证类

有一些功能我们想让用户登录后才能访问,不登录则报没有权限,可以按以下方法配置

from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated

# 在需要认证的类中添加以下两个配置
authentication_classes = [JSONWebTokenAuthentication]   # 验证token对不对(不验证是否携带用户信息)
permission_classes = [IsAuthenticated]  # 验证是否携带用户信息

使用postman发请求,先使用login接口获取用户的token,然后再get请求中的headers中添加 Authorization 的键,值是 “jwt token”,如下图:
image

authentication.py

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.settings import api_settings
from user.models import UserInfo
import jwt


jwt_decode_handler = api_settings.JWT_DECODE_HANDLER


class JsonWebTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 在请求头中取出token
        token = request.META.get('HTTP_TOKEN')
        if token:
            try:
                payload = jwt_decode_handler(token)
                user = UserInfo.objects.get(pk=payload.get('user_id'))
                # user = UserInfo(pk=payload.get('user_id'), username=payload.get('username'))
                return user, token
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('用户会话已过期,请重新登录')
            except jwt.DecodeError:
                raise AuthenticationFailed('用户认证失败,请重新登录')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('用户认证无效,请重新登录')
            except Exception as e:
                raise AuthenticationFailed('未知异常')
        raise AuthenticationFailed('您未登录,请先登录')