79- drf三大认证的配置及使用方法

目录

  • 三大认证

    • 一、身份认证

      • 1、身份认证配置
      • 2、drf提供的身份认证类(了解)
      • 3、rf-jwt提供的身份认证类(常用)
      • 4、自定义身份认证类(需要自定义签发token时用)
      • 5、自定义签发token及多方式登陆
    • 二、权限认证
      • 1、权限认证配置
      • 2、drf提供的权限认证类
      • 3、自定义权限认证类
    • 三、节流认证(频率认证)
      • 1、节流认证配置
      • 2、drf提供的节流认证类
      • 3、自定义节流认证类

三大认证

一、身份认证

1、身份认证配置

1.1 全局配置身份认证模块

身份认证组件一般都配置在全局settings中。

# settings.py
# drf框架自定义配置
REST_FRAMEWORK = {
    # 认证组件
    'DEFAULT_AUTHENTICATION_CLASSES': [
        # 'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.BasicAuthentication'
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
    ],
}

1.2 局部配置身份认证模块

在视图类中用authentication_classes类属性配置身份认证模块:

# views.py
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class UserListViewSet(mixins.ListModelMixin, GenericViewSet):
    authentication_classes = [JSONWebTokenAuthentication]

    queryset = models.User.objects.filter(is_active=True).all()
    serializer_class = serializers.UserModelSerializer

2、drf提供的身份认证类(了解)

其中BaseAuthentication是用来自定义身份认证类需要继承的基类。

其他的类是drf默认提前写好的几种身份认证类,可以直接使用:

BasicAuthentication

SessionAuthentication

TokenAuthentication

def get_authorization_header(request):
    # 前台在请求头用authorization携带认证字符串token给后台
    auth = request.META.get('HTTP_AUTHORIZATION', b'')
    # auth == token字符串  将其编码成二进制
    if isinstance(auth, str):
        # Work around django test client oddness
        auth = auth.encode(HTTP_HEADER_ENCODING)
    return auth

class BasicAuthentication(BaseAuthentication):
    www_authenticate_realm = 'api'

    def authenticate(self, request):
        auth = get_authorization_header(request).split()
        # auth按空格拆分,拆分的列表结果长度为2才合法

        if not auth or auth[0].lower() != b'basic':
            # 没有token,认证方法直接返回None,代表游客(匿名用户)
            return None
        # 可以推论出auth拆分的结果为2份,结构为:['basic','token字符串']
        if len(auth) == 1:
            msg = _('Invalid basic header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid basic header. Credentials string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)
            # 结论:提交了token,格式有误,抛异常,代表非法用户

        try:
            # 反解token(auth是被拆分的列表,0是头,1是token)
            auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')
        except (TypeError, UnicodeDecodeError, binascii.Error):
            msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
            raise exceptions.AuthenticationFailed(msg)
            # 结论:提交了token,格式有误,抛异常,代表非法用户

        userid, password = auth_parts[0], auth_parts[2]
        return self.authenticate_credentials(userid, password, request)
        # 结论:提交了token,解析成功,返回(user,None)组成的元组,代表合法用户
        # 元组0位user会被储存到request.user中,
        # 元组1位token会被存储到request.auth中,通常可以不用保存,所以可以用None填充

    def authenticate_credentials(self, userid, password, request=None):
        """
        Authenticate the userid and password against username and password
        with optional request for context.
        """
        credentials = {
            get_user_model().USERNAME_FIELD: userid,
            'password': password
        }
        user = authenticate(request=request, **credentials)

        if user is None:
            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

        if not user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        return (user, None)

    def authenticate_header(self, request):
        return 'Basic realm="%s"' % self.www_authenticate_realm

class SessionAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # Get the session-based user from the underlying HttpRequest object
        user = getattr(request._request, 'user', None)

        # Unauthenticated, CSRF validation not required
        if not user or not user.is_active:
            return None

        self.enforce_csrf(request)

        # CSRF passed with authenticated user
        return (user, None)

class TokenAuthentication(BaseAuthentication):
    keyword = 'Token'
    model = None

    def authenticate(self, request):
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != self.keyword.lower().encode():
            return None

        if len(auth) == 1:
            msg = _('Invalid token header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid token header. Token string should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)

        try:
            token = auth[1].decode()
        except UnicodeError:
            msg = _('Invalid token header. Token string should not contain invalid characters.')
            raise exceptions.AuthenticationFailed(msg)

        return self.authenticate_credentials(token)

3、rf-jwt提供的身份认证类(常用)

rf-jwt为我们提供了其已经写好的身份认证类:JSONWebTokenAuthentication

特点:

前端在向后端发送请求时需携带的token格式为:

{'Authorization':'jwt abc.def.xyz'}  // token需以jwt开头

后端如何配置:

from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class UserListViewSet(ListModelMixin,GenericViewSet):
    # ---------------三大认证配置---------------我是分割线
    # authentication_classes = [authentications.MyAuthentication]
    authentication_classes = [JSONWebTokenAuthentication]

    # -----------------正常逻辑-----------------我是分割线
    queryset = models.User.objects.filter(is_active=True).all()
    serializer_class = serializers.UserModelSerializer

4、自定义身份认证类(需要自定义签发token时用)

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

如何自定义身份认证类:

  1. 继承BaseAuthentication续写Authentication身份认证类:
  2. 重写authenticate方法;
  • 从请求头中拿到前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台约定)

    • 如果设置了反爬等措施,校验一下反爬(头 token)
  • 没有token,返回None,代表游客
  • 有token,进入校验
    • 不通过:抛AuthenticationFailed异常,代表非法用户
    • 通过:返回 (user, token),代表合法用户
from rest_framework.authentication import BaseAuthentication

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 不设置任何身份认证规则,直接全部通过,进入下一轮认证(权限认证)
        pass

5、自定义签发token及多方式登陆

重点:

  1. token只能由 登录接口 签发;
  2. 登录接口也是APIView的子类,使用一定会进行‘身份认证‘和‘权限认证‘组件的校验。

结论:不管系统默认、或是全局settings配置的是何认证与权限组件,登录接口不用参与任何认证与权限的校验所以,登录接口一定要进行‘身份认证‘与‘权限认证‘的局部禁用

# views.py
from rest_framework.views import APIView
class LoginAPIView(APIView):
    authentication_classes = []
    pagination_class = []
    permission_classes = []
    def post(self,request,*args,**kwargs):
        user_ser = serializers.LoginModelSerializer(data=request.data)
        user_ser.is_valid(raise_exception=True)
        return APIResponse(results={
            'username':user_ser.content.get('user').username,
            'token':user_ser.content.get('token')
        })

# serializers.py
from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
class LoginModelSerializer(serializers.ModelSerializer):
    username = serializers.CharField(
        max_length=64,
        min_length=3
    )
    password = serializers.CharField(
        max_length=64,
        min_length=3
    )

    class Meta:
        model = models.User
        fields = ['username','password']

    # 在全局钩子中完成token的签发
    def validate(self, attrs):
        # 先从model表中查出user对象
        user = self._validate_user(attrs)
        # 将user对象包装进载荷中
        payload = jwt_payload_handler(user)
        # 将载荷签发入token
        token = jwt_encode_handler(payload)
        # 将对象和token储存进serializer对象中,就可以在视图类中调用
        self.content = {
            'user':user,
            'token':token
        }
        return attrs

    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()  # type:models.User
        else:
            user = models.User.objects.filter(username=username).first()  # type:models.User

        if not user or not user.check_password(password):
            raise serializers.ValidationError({'message':'用户信息系有误!请重新登录!'})

        return user

二、权限认证

1、权限认证配置

1.1 全局配置权限认证模块

一般权限认证不做全局配置,因为每个功能对应不同的权限,不好配。

1.2 局部配置权限认证模块

使用permission_classes类属性配置:

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

class UserViewSet(ViewSet):
    # 配置django默认提供的权限认证模块
    permission_classes = [IsAuthenticated]

2、drf提供的权限认证类

drf默认提供了几种权限认证模块:

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

- AllowAny                  |  游客和登录用户有全权限
- IsAuthenticated           |  只有登录用户有全权限
- IsAdminUser               |  只有后台用户(admin用户)有全权限
- IsAuthenticatedOrReadOnly |  游客有读权限,登录用户有全权限

3、自定义权限认证类

如果有特殊需要,需要自定义权限类

如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限

如何自定义权限类:

  1. 继承BasePermission续写permission类;
  2. 重写has_permission方法;
    • 根据需求,request和view的辅助,制定权限规则判断条件
    • 如果条件通过,返回True
    • 如果条件不通过,返回False
# permission.py
from rest_framework.permissions import BasePermission
# VIP用户权限
class VIPUserPermission(BasePermission):
    def has_permission(self, request, view):
        for group in request.user.groups.all():
            # 存在于vip组即有权限
            if group.name.lower() == 'vip':
                return True
        # 否则没有权限
        return False

# views.py
class UserViewSet(ViewSet):
    # 局部配置哪些权限可以执行此操作
    permission_classes = [permissions.VIPUserPermission]

    def retrieve(self,request,*args,**kwargs):
        return APIResponse(results={
            'username':request.user.username,
            'email':request.user.email,
            'mobile':request.user.mobile,
            'create_time':request.user.date_joined,
        })

三、节流认证(频率认证)

1、节流认证配置

需全局与局部配置配合。

局部配置节流模式,全局配置节流模式的流量。

1.1 全局配置节流认证模块

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

1.2 局部配置节流认证模块

使用throttle_classes类属性配置:

from rest_framework.viewsets import ViewSet
class UserViewSet(ViewSet):

    throttle_classes = []

2、drf提供的节流认证类

drf默认提供了几种节流认证模式:

from rest_framework.throttling import AnonRateThrottle,UserRateThrottle,ScopedRateThrottle

- AnonRateThrottle      |    scope = 'anon'
- UserRateThrottle      |    scope = 'user'
- ScopedRateThrottle    |    scope_attr = 'throttle_scope'

3、自定义节流认证类

如果有特殊需要,需要自定义频率类.

如:对ip进行限次、对电话进行限制、对视图某些信息进行限次.

如何自定义:

  1. 继承SimpleRateThrottle节流基类续写throrrle类;
  2. 设置scope字符串类属性,同时在settings中进行drf配置DEFAULT_THROTTLE_RATES
    • eg: DEFAULT_THROTTLE_RATES = {‘mobile‘: ‘1/min‘}
  3. 重写get_catch_key方法
    • 返回与限制条件有关的字符串,表示限制
    • 返回None,表示不限制
# throttles.py
from rest_framework.throttling import SimpleRateThrottle
class ModileRateThrottle(SimpleRateThrottle):
    scope = 'mobile'
    def get_cache_key(self, request, view):
        # 游客和没有手机号的用户不做限制
        if not request.user.is_authenticated or request.user.mobile:
            return None
        # 设置用户唯一识别码
        return self.cache_format % {
            'scope':self.scope,
            'ident':request.user.mobile
        }

# views.py
from rest_framework.viewsets import ViewSet
class UserViewSet(ViewSet):
    # throttle_classes = [UserRateThrottle]
    throttle_classes = [throttles.ModileRateThrottle]

    def retrieve(self,request,*args,**kwargs):
        return APIResponse(results={
            'username':request.user.username,
            'email':request.user.email,
            'mobile':request.user.mobile,
            'create_time':request.user.date_joined,
        })

原文地址:https://www.cnblogs.com/bowendown/p/12150431.html

时间: 2024-07-29 19:22:11

79- drf三大认证的配置及使用方法的相关文章

drf 三大认证详解

目录 drf 三大认证: 认证: 权限: 认证与权限组件绑定使用: 频率: 多方式登录: drf 三大认证: 认证: # 全局配置: -在全局(认证组件只能决定request.user,不是断定权限的地方,所以一般配置全局) REST_FRAMEWORK = { # 认证组件 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' ], } # 局部禁用(

drf三大认证

源码分析 dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证 # 认证组件:校验用户(游客,合法用户,非法用户) # 游客:代表校验通过直接进入下一步校验, # 合法用户:代表校验通过,将用户存储在request.user中,在进入下一步校验 # 非法用户:代表校验失败,抛出异常,返回403权限异常结果 self.perform_authentication(request) # 权限组件:校验用户权限,必须登录,所有用户登录读写,游

drf三大认证:认证组件-权限组件-权限六表-自定义认证组件的使用

三大认证工作原理简介 源码分析: from rest_framework.views import APIView 源码分析入口: 内部的三大认证方法封装: 三大组件的原理分析: 权限六表分析 基于用户权限访问控制的认证(RBAC):Role-Based-Access-Control;基于auth的认证规则(了解). Django框架采用的是RBAC认证规则:通常分为:三表规则.五表规则.Django采用的是六表规则. 三表:用户表.角色表.权限表 五表:用户表.角色表.权限表.用户角色关系表.

?DRF?-----三大认证组件--认证组件

认证组件 铺垫: 源码分析 入口: restframework 框架内的 views 下的 APIView 的 dispatch方法 组件的最下面 有三个方法   分别是 认证组件  权限组件 和 频率组件 perform_authentication (认证组件) 校验用户 - 游客 合法用户 非法用户 游客: 代表校验通过 进入下一步校验 (权限校验) 合法用户: 代表校验通过 将用户 存储在 request.user 中 再进行下一步校验 非法用户: 代表校验失败 抛出异常 返回403 权

drf三大认证补充

频率认证 源码分析部分 def check_throttles(self, request): for throttle in self.get_throttles(): if not throttle.allow_request(request, self): self.throttled(request, throttle.wait()) def throttled(self, request, wait): #抛异常,可以自定义异常,实现错误信息的中文显示 raise exceptions

自定义路由组件,Django的admin后台管理,DRF的三大认证,jwt认证

目录 一.自定义路由组件 1. 为什么要自定义路由组件 2. 自定义路由组件实例 二.Django的admin后台管理 三.DRF的三大认证组件概括 1. 认证组件 2. 权限组件 3. 频率组件 四.Django中的用户权限管理 五.jwt认证 1. jwt认证和普通session认证的区别 2. jwt认证介绍 (1)jwt的原理 (2)jwt三部分的内容 3. jwt的签发算法 (1)第一步:头部算法 (2)第二步:载荷部分的算法 (3)第三步:签名部分的算法 (4)第四步:连接生成tok

drf框架 6 视图集与路由组件(开发最常用、最高级) 三大认证原理 RBAC认证规则

准备工作 models.py from django.db import models # 基类:是抽象的(不会完成数据库迁移),目的是提供共有字段的 class BaseModel(models.Model): is_delete = models.BooleanField(default=False) updated_time = models.DateTimeField(auto_now_add=True) class Meta: abstract = True # 必须完成该配置 cla

drf之三大认证

一.前言 ? 我们知道drf的APIView类的as_view直接对原生django的csrf进行了禁用,是什么让drf有如此底气?从之前对drf的源码分析可以看到,三条语句. self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request) 这就是drf的三大认证. 二.用户认证 1.drf的用户认证 ? 我们的某些接口需要对用户进行辨别,那么我们该如何区分A用户

DRF框架 之基础配置

Vue框架的总结 """ 1.vue如果控制html 在html中设置挂载点.导入vue.js环境.创建Vue对象与挂载点绑定 2.vue是渐进式js框架 3.vue指令 {{ }} v-text|html => 限制一次性渲染 v-once v-if|show v-if v-else-if v-else v-for v-model v-bind [c1, c2] | {active: isActive} v-on fn | fn(...) | fn($event, .