drf-jwt第三方插件,DRF的三大认证的具体使用,多方式登陆的实现

Posted mcoming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了drf-jwt第三方插件,DRF的三大认证的具体使用,多方式登陆的实现相关的知识,希望对你有一定的参考价值。

[TOC]

一、 JWT认证的使用

1. 第三方drf-jwt插件

  • 借助第三方的drf-jwt插件,进行jwt认证,完成token的签发和校验和刷新(需要先手动下载,命令是:pip install djangorestframework-jwt

  • drf-jwt插件其实就是一个小的应用,包含了settings,views,utils,serializers,models等文件。

  • 有关token的配置参数就在插件的settings文件中,我们也可以在自己项目的settings文件中配置后,然后覆盖掉插件中的默认配置,达到自定义token配置的目的。

    • 项目的settings文件中,当然还可以配置token的其他参数
      
      # drf-jwt自定义配置
      import datetime
      
      JWT_AUTH = {
          # 过期时间
          ‘JWT_EXPIRATION_DELTA‘: datetime.timedelta(seconds=300),
          # 是否允许刷新
          ‘JWT_ALLOW_REFRESH‘: False,
          # 最大刷新的过期时间
          ‘JWT_REFRESH_EXPIRATION_DELTA‘: datetime.timedelta(days=7),
      }
      
      
  • 注意:在token的签发中,有两个方法很重要

*****jwt_payload_handler和jwt_encode_handler方法*****

from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler

# 1. 用user对象包装成payload载荷
payload = jwt_payload_handler(user)
# 2. 利用payload载荷签发token(jwt认证的头部在系统内部已写死,不需要我们参与编写了)
token = jwt_encode_handler(payload)

2. 利用第三方插件的views完成token操作

1. 应用的urls文件中:
from django.conf.urls import url, include

from .router import router
# eg: router.register(‘users‘, UserModelViewSet, basename=‘user‘)

from rest_framework_jwt.views import ObtainJSONWebToken, obtain_jwt_token, refresh_jwt_token, verify_jwt_token

urlpatterns = [
	# ObtainJSONWebToken.as_view()等价于obtain_jwt_token
    # url(r‘^login/$‘, ObtainJSONWebToken.as_view()),
    url(r‘^login/$‘, obtain_jwt_token),  # 登录接口(签发token)
    url(r‘^refresh/$‘, refresh_jwt_token),  # 刷新token接口
    url(r‘^verify/$‘, verify_jwt_token),  # 校验token接口

    url(r‘‘, include(router.urls))
]

二、DRF的三大认证的使用

  • 三大认证组件:认证组件、权限组件、频率组件

    • 认证组件:身份认证(游客/合法用户/非法用户)
    • 权限组件:针对游客和合法用户对某一视图函数的访问权限
    • 频率组件:限制某一视图函数在一定时间内被访问的次数
  • 三大组件是按流水线式轮流进行,即:先进行认证——》再权限校验——》最后是频率校验

  • 借助第三方的drf-jwt插件,进行jwt认证,完成token的签发和校验和刷新(需要先手动下载,命令是:pip install djangorestframework-jwt

    • drf-jwt插件:
      
      	提供了 签发token、校验token、刷新token的三个视图类
      	认证组件中(校验jwt token,得到登录用户user对象,存储到request.user中)
      
  • 在视图类的自身逻辑之前书写需要的三大认证功能(注意是之前),即在视图类的下面的第一行书写三大认证。

三、认证组件的使用

1. 认证组件的用法和注意点

  • 实际开发中对DRF自带的认证功能需求大,且一般在全局中配置认证组件。

  • 自定义的认证功能在实际开发中需求较少,但也可能会出现。

  • 注意:登录接口不用参与任何认证与权限的校验

  • 在认证功能中,认证类返回值有以下3中情况

    • 1. 没有token或者前台提交的token格式错误
      	返回 None 表示游客
      
      2. 有正常的token
      	token校验不通过,则抛出AuthenticationFailed异常,代表非法用户
      
      3. 有正常的token
      	token校验通过,返回 (user,token) ,表示合法用户(user是用户对象)
      

2. 认证组件使用步骤

(1)使用DRF自带的认证功能(非登陆功能中)

  • 使用步骤:
1. 在settings文件中配置drf框架的认证组件

REST_FRAMEWORK = {
    # 异常模块:异常处理函数
    ‘EXCEPTION_HANDLER‘: ‘api.exception.exception_handler‘,

    # 配置全局认证组件
    ‘DEFAULT_AUTHENTICATION_CLASSES‘: [
        
 ‘rest_framework_jwt.authentication.JSONWebTokenAuthentication‘
    ],

    # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置
    ‘DEFAULT_THROTTLE_RATES‘: {
        ‘user‘: ‘5/min‘,
        ‘anon‘: ‘3/min‘,
        ‘mobile‘: ‘1/min‘
    },
}


2. 书写视图类的正常逻辑代码

(2)使用自定义的认证类(非登录功能中)

  • 使用步骤:
# 这里自定义的认证类是在局部配置的,但一般是在settings文夹中进行全局配置

1. 在应用文件夹下新建文夹,书写自定义的认证类

如: 新建 authentications.py文夹,内部定义继承了BaseAuthentication类的MyAuthentication类

2. 在视图类的正常逻辑代码之前进行认证类的配置

from . import authentications
authentication_classes = [authentications.MyAuthentication]

3. 书写视图类的正常逻辑代码

(3)自定义认证类实例

‘‘‘
自定义认证类
1) 如果使用session认证,drf默认提供了SessionAuthentication
2) 如果使用drf-jwt认证框架,drf-jwt框架提供了JSONWebTokenAuthentication
3) 如果是自定义签发与校验token,才需要将校验token的算法封装到自定义的认证类中
‘‘‘

from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        """
        1) 从请求头中拿到前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台约定)
              -- 如果设置了反爬等措施,校验一下反爬(头 token)
        2)没有token,返回None,代表游客
        3)有token,进入校验
              -- 不通过:抛AuthenticationFailed异常,代表非法用户
              -- 通过:返回 (user, token),代表合法用户
        """
        pass

四、权限组件的使用

1. 权限组件的用法和注意点

  • 权限校验一般进行局部配置,因为不同的用户对视图类的权限差别很大,所以要分别配置(当然也可以同时进行全局配置和局部配置)

  • 在实际开发中,DRF自带的权限组件功能和自定义权限类两者都会有需求

  • 注意:登录接口不用参与任何认证与权限的校验

  • 权限类的返回值有两种情况

    • 1. 返回 True  # 条件通过,即有权限
      2. 返回 False  # 条件不通过,即没有权限
      

2. 权限组件使用步骤

(1)使用DRF自带的权限功能(非登录功能中)

  • 使用步骤
1. 视图类中进行局部配置DRF自带的权限组件

from rest_framework.permissions import IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly

permission_classes = [IsAuthenticated]
permission_classes = [IsAdminUser]

2. 书写视图类的正常逻辑代码

(2)使用自定义的权限类

1. 在应用文件夹下新建一个文件,来自定义权限类

如:新建permissions.py文件,内部定义继承了BasePermission类的MyPermission类

2. 视图类中进行局部配置自定义的权限组件

from . import permissions
permission_classes = [permissions.MyPermission]

3. 书写视图类的正常逻辑代码

(3)自定义权限类实例

"""
自定义权限类
1) drf默认提供了一些权限类
    AllowAny:游客和登录用户有全权限
    IsAuthenticated:只有登录用户有全权限
    IsAdminUser:只有后台用户(admin用户)有全权限
    IsAuthenticatedOrReadOnly:游客有读权限,登录用户有全权限
2)如果有特殊需要,需要自定义权限类
    如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限
"""

from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        1) 根据需求,request和view的辅助,制定权限规则判断条件
        2)如果条件通过,返回True
        3)如果条件不通过,返回False
        """
        print(request.user, request.auth)
        return False


# VIP用户权限
class VIPUserPermission(BasePermission):
    def has_permission(self, request, view):
        for group in request.user.groups.all():
            if group.name.lower() == ‘vip‘:
                return True
        return False

五、频率组件的使用

1. 频率组件的用法和注意点

  • DRF自带的频率组件只有频率限制的条件,需要我们自己实现限制功能。

  • 频率组件都需要我们自定义频率类,因此需求很大

  • 频率校验一般做局部配置,但是频率校验的限制条件在settings中配置

  • 频率类的返回值有两种

    • 1. 返回 None  # 表示不限制
      
      2. 返回与限制条件有关的字符串,表示限制(注意此处的返回值的写法)
      

2. 频率组件使用步骤

  • 直接就是使用自定义的频率类
1. 在应用文件夹下新建一个文件,来自定义频率类

如:新建一个throttles.py文件,其内部定义一个继承了SimpleRateThrottle类的MobileRateThrottle类

2. 在settings文件中配置频率限制条件

# drf框架自定义配置
REST_FRAMEWORK = {
    
    # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置
    ‘DEFAULT_THROTTLE_RATES‘: {
        ‘user‘: ‘5/min‘,
        ‘anon‘: ‘3/min‘,
        ‘mobile‘: ‘1/min‘
    },
}

3. 在视图类中进行局部配置频率校验

from . import throttles
throttle_classes = [throttles.MobileRateThrottle]

4. 书写视图类的正常逻辑代码

(2)自定义频率类实例

"""
自定义频率类
1) drf默认提供了一些频率类 
    AnonRateThrottle:只对游客进行频率限制
    UserRateThrottle:对所有用户进行频率限制
2)如果有特殊需要,需要自定义频率类
    如:对ip进行限次、对电话进行限制、对视图某些信息进行限次
"""

from rest_framework.throttling import SimpleRateThrottle

class MobileRateThrottle(SimpleRateThrottle):
    """
    1)设置scope字符串类属性,同时在settings中进行drf配置DEFAULT_THROTTLE_RATES
        eg: DEFAULT_THROTTLE_RATES = {‘mobile‘: ‘1/min‘}
    2)重写get_catch_key方法:
        返回与限制条件有关的字符串,表示限制
        返回None,表示不限制
    """
    scope = ‘mobile‘
    def get_cache_key(self, request, view):
        if not request.user.is_authenticated or not request.user.mobile:
            return None  # 匿名用户 或 没有电话号的用户 都不限制

        # 只要有电话号的用户才进行限制
        return self.cache_format % {
            ‘scope‘: self.scope,
            ‘ident‘: request.user.mobile
        }

六、多方式登陆的实现

  • 实现用户名、邮箱、电话号码三种方式的登陆
  • 同时实现登陆功能的jwt认证的 token的签发

1. 登陆功能中的注意点

  1. token只能由登陆接口签发
  2. 登陆接口也是APIView的子类,使用就一定会进行认证、权限的校验,但是实际上,登陆接口不能参与任何认证和权限的校验,所以要进行认证和权限校验的局部禁用。
  3. 登陆所需的数据和登陆校验以及token的签发都是通过序列化类完成的。
  4. 注意:因为登陆是需要用户提交数据的,所以走得是post请求。但是当走post请求时,系统会默认当前要进行的是增功能。因此,我们在序列化类中,要把系统字段改为同名的自定义反序列化字段。
  • 在进行token的签发时,需要用到drf-jwt插件来完成

2. 多方式登陆的实现代码

1. 应用的urls文件中:
from django.conf.urls import url, include
from . import views
from .router import router

router.register(‘users‘, views.UserListViewSet, basename=‘user‘)  # basename就是别名


urlpatterns = [

    # 自定义签发token的登录login接口
    url(r‘^login/$‘, views.LoginAPIView.as_view()),

    url(r‘‘, include(router.urls))
]

2. 自定义的序列化文件中:

# 登陆视图类对应的序列化类

# 导入drf-jwt插件,利用其中的两个方法完成token的签发
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler

import re

class LoginModelSerializer(serializers.ModelSerializer):
    # post请求,序列化默认当做create动作进行校验,需要校验数据库,执行create动作,username会抛用户已存在异常
    # 抛用户已存在异常是多余的,所以自定义系统校验规则即可,即自定义反序列化的同名字段即可
    
    username = serializers.CharField(min_length=3, max_length=16)
    password = serializers.CharField(min_length=3, max_length=16)
    
    class Meta:
        model = models.User
        fields = (‘username‘, ‘password‘)

    # 用全局钩子,完成token的签发
    def validate(self, attrs):
        # 1)通过 username 和 password 完成多方式登录校验,得到user对象
        user = self._validate_user(attrs)  # 自定义方法得到user对象
        # 2)用user对象包装成payload载荷
        payload = jwt_payload_handler(user)
        # 3)利用payload载荷签发token(jwt认证的头部在系统内部已写死,不需要我们参与编写了)
        token = jwt_encode_handler(payload)
        # 4)将user与token存储到serializer对象中,方便在视图类中使用
        self.content = {
            ‘user‘: user,
            ‘token‘: token
        }
        return attrs
	
    # 利用正则,匹配出不同格式的username,再分别进行校验
    def _validate_user(self, attrs):
        username = attrs.get(‘username‘)
        password = attrs.get(‘password‘)

        if re.match(r‘.*@.*‘, username):  # 邮箱
            user = models.User.objects.filter(email=username).first()  # type: models.User
        elif re.match(r‘^1[3-9][0-9]{9}$‘, username):  # 电话
            user = models.User.objects.filter(mobile=username).first()
        else:  # 用户名
            user = models.User.objects.filter(username=username).first()

        if not user or not user.check_password(password):
            raise serializers.ValidationError({‘message‘: ‘用户信息异常‘})

        return user

以上是关于drf-jwt第三方插件,DRF的三大认证的具体使用,多方式登陆的实现的主要内容,如果未能解决你的问题,请参考以下文章

drf-jwt认证组件权限组件频率组件的使用

频率类组件-认证规图分析-JWT认证-drf-jwt插件

drf-jwt认证

drf-JWT认证

jwt认证规则

基于drf-jwt的全局 局部 认证(校验 token)