Simple JWT

Simple JWT

安装

pip install djangorestframework_simplejwt

settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication', # 必须配置的认证类
    ],
    "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",), 
  # 当你在验证token的时候是需要配置一个权限类的,IsAuthenticated是drf自带的,在这里全局配置之后那么你的所有的视图就不必一个个配置权限类了
}

注意

所有的用户验证所使用的表是django自带的user表

简单实现生成token及验证

urls.py

from rest_framework_simplejwt.views import (
    TokenObtainPairView,   # 双token
    TokenRefreshView,
    TokenObtainSlidingView,  # 下面两个是单token,用法一样
    TokenRefreshSlidingView
)


urlpatterns = [
    path('test-auto-token', TokenObtainPairView.as_view()),
    path('refresh', TokenRefreshView.as_view()),
]

获取token

默认是使用username和password去登陆返回token

image

刷新token

image

自定义使用email或者phone登陆

backend.py

from django.contrib.auth.backends import ModelBackend

class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        # print(request.data) 参考请求的其他数据
        # print(request.data['demo']) 比如说key是demo的数据用来做你要的数据校验
        try:
            # 小编这里添加了一个手机验证和邮箱验证,用户名被我去掉了,如果需要其他验证再加就ok了
            try:
                user = Users.objects.get(Q(email=username) | Q(mobile=username))
            except Exception:
                raise serializers.ValidationError({'': '账号没有注册'})

            if user.check_password(password):
                return user
            else:
                # 如果不想密码登录也可以验证码在这里写
                # 这里做验证码的操作
                raise serializers.ValidationError({'': '密码错误'})

        except Exception as e:
            raise e

setting.py

# 自定义JWT校验
AUTHENTICATION_BACKENDS = (
    'app01.backend.CustomBackend',
)

image

定制化payload和token(双token)

views.py

from rest_framework_simplejwt.views import TokenObtainPairView

class TestJwtToken(TokenObtainPairView):
    serializer_class = MyTokenObtainSerializer

serializers.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class MyTokenObtainSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['username'] = user.username  # 这里的username会加入到payload里
        return token

    def validate(self, attrs):
        data = super().validate(attrs)

        refresh = self.get_token(self.user)

        data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)
        data['email'] = self.user.email  # 这里会在接口里返回email字段,看下图

        return data

在get_token方法里加字段是在token的payload里去添加数据,在使用base64解码的时候会显示出你添加的字段

b'{"typ":"JWT","alg":"HS256"}{"token_type":"refresh","exp":1669017564,"jti":"86a53bd885374f1ca8715e1e3f302a3e","user_id":2,"username":"admin"}
# 在这里username就被添加进了payload里了

在validate方法里的data字典加字段,就是在返回token的response里加数据

image

自定义生成token(可塑性高)

双token

from rest_framework_simplejwt.tokens import RefreshToken

class MyReturnToken(APIView):
    def get(self, request, *args, **kwargs):
        user = Client.objects.get(pk=1)
        refresh = RefreshToken.for_user(user)  # 只要传user对象就行了
        return Response({
            'refresh': str(refresh),
            'access': str(refresh.access_token)
        })

image

单token

from rest_framework_simplejwt.tokens import SlidingToken

class MyReturnToken(APIView):
    def get(self, request, *args, **kwargs):
        user = Client.objects.get(pk=2)
        # refresh = RefreshToken.for_user(user)
        token = SlidingToken.for_user(user)
        print(token)
        print(type(token))
        return Response(data=str(token))

image

认证和权限特点

在drf中,认证、权限、频率有一个共性,使用顺序是

  • 视图配置>settings文件配置>def配置文件配置
  • 当视图配置了,那就不会使用settings文件配置的了

drf配置文件内默认的认证类和权限类

'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]

当你是使用simple jwt去认证的时候,全局加的JWTAuthentication认证会返回一个user对象,然后全局的权限类IsAuthenticated会验证该user对象是否存在并且被认证过,如果被认证了那么就会返回Ture,反之亦然。

class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_authenticated)
      
# 在JWTAuthentication认证类里面刚获得user对象user.is_authenticated就已经是Ture了

如果你没有登陆去访问其他接口的话,那么你是以匿名用户AnonymousUser的身份访问的,但是权限认证是不能通过的,但是你要是在视图里的权限类里写空,就比如permission_classes = ( ), 那么你用匿名用户也可以访问该视图,只是没有user信息。

认证类写为空:
image

权限类写为空:

image

一般如果要是在登陆认证的接口,那么视图里面的认证和权限类都写空( ),这样不管是自己登陆不需要携带token,写第三方接口时,第三方就能直接调用该接口,不需要token,但是需要你手动的去做一些其他的校验来保证数据的安全

posted @ 2022-11-22 22:05  zong涵  阅读(949)  评论(2编辑  收藏  举报