ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-01-02 21:52:41  阅读:189  来源: 互联网

标签:插件 自定义 jwt 认证 token user 权限 drf


目录

一、 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

标签:插件,自定义,jwt,认证,token,user,权限,drf
来源: https://www.cnblogs.com/Mcoming/p/12142204.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有