django学习笔记--drf认证、权限、限流记录

drf基础配置

版本:

Django              3.2
djangorestframework 3.13.1

纯净版配置:

INSTALLED_APPS = [
    # 'django.contrib.admin',
    # 'django.contrib.auth',
    # 'django.contrib.contenttypes',
    # 'django.contrib.sessions',
    # 'django.contrib.messages',
    'django.contrib.staticfiles',
    'api.apps.ApiConfig',
    'rest_framework'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    # 'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    # 'django.contrib.auth.middleware.AuthenticationMiddleware',
    # 'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                # 'django.contrib.auth.context_processors.auth',
                # 'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": None
}

路由

from django.contrib import admin
from django.urls import path
from api import views

urlpatterns = [
    # path('admin/', admin.site.urls),
    path('users/', views.UserView.as_view()),
]```
###视图
```python
from rest_framework.views import APIView
from rest_framework.response import Response


class UserView(APIView):
    def get(self, request):
        return Response("...")

request参数:

路径参数

# urls.py
urlpatterns = [
    path('users/<str:version>/<int:pid>/',views.UserView.as_view())
]
# views.py
class UserView(APIView):
    def get(self, request,version,pid):
        print(version,pid)
        print(self.kwargs) #{version:'v1','pid':123}
        return Response("ok")

drf request对象获取参数示例:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated

class MyView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):
        # 获取路径参数
        item_id = kwargs.get('item_id')

        # 获取查询参数
        search_query = request.query_params.get('search', '')

        # 获取请求头
        auth_token = request.headers.get('Authorization')

        # 获取表单或 JSON 数据
        data_field = request.data.get('data_field')

        # 获取文件
        uploaded_file = request.FILES.get('file')

        # 获取用户信息
        user = request.user

        return Response({
            "item_id": item_id,
            "search_query": search_query,
            "auth_token": auth_token,
            "data_field": data_field,
            "uploaded_file_name": uploaded_file.name if uploaded_file else None,
            "user": {"username": user.username, "email": user.email},
        })

认证

#基础类,定义一个认证类,需要实现如下基础类两个方法
class BaseAuthentication:
    def authenticate(self, request):
        raise NotImplementedError(".authenticate() must be overridden.")
    def authenticate_header(self, request):
        pass
# 简单实现示例:
from rest_framework.authentication import BaseAuthentication
from api.models import User

class MyAuthentication(BaseAuthentication):

    def authenticate(self, request):
        token=request.headers.get('token')
        user=User.objects.filter(token=token).first()
        if user:
            return user,token
        return None,None

    def authenticate_header(self, request):
        return 'Token'

源码路径

APIView,dispatch方法会调用self.initial(request, *args, **kwargs)
self.initial会依次调用下面三个方法分别为认证、权限、限流

        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)

下面我们先看下认证源码,上述的self都是APIView的子类对象, self.perform_authentication(request)调用request.user进入Request对象,调用Request如下方法,self.authenticators是配置在settings.REST_FRAMEWORK下的DEFAULT_AUTHENTICATION_CLASSES属性或者APIView子类的authentication_classes属性配置里,优先取view类里配置的,没有再取settings公共的

    def _authenticate(self):
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

备注:认证类默认前一个未认证会继续下一个,有一个认证成功就会终止认证继续后面逻辑,若认证抛出异常也会终止认证并返回,所有认证都没通过也会继续执行后面逻辑

权限

#自定义权限类,限制某个角色才能访问
from rest_framework.permissions import BasePermission

class PermissionA(BasePermission):
    message = {"code": 1003, 'data': "无权访问"}

    def has_permission(self, request, view):
        if request.user.role == 2:
            return True
        return False

    # 暂时先这么写
    def has_object_permission(self, request, view, obj):
        return True

源码简单分析:读取当前View类(如:UserView)配置的permission_classes,若未配置则取APIView默认配置settings.REST_FRAMEWORK的DEFAULT_PERMISSION_CLASSES属性

    def check_permissions(self, request):
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )

备注:权限类默认有一个失败就返回异常,若想定制满足任意权限,可在APIView子类修改check_permission方法

def check_permissions(self, request):
        for permission in self.get_permissions():
            if permission.has_permission(request, self):
                return #有任一权限返回
        #无任何权限通过走此逻辑
        self.permission_denied(
            request,
            message=getattr(permission, 'message', None),
            code=getattr(permission, 'code', None)
        )

限流

class MyRateThrottle(SimpleRateThrottle):
    cache = default_cache  # 访问记录存放在django的缓存中(需设置缓存)
    scope = "user"  # 构造缓存中的key
    cache_format = 'throttle_%(scope)s_%(ident)s'

    '''设置访问频率,例如:1分钟允许访问10次,可在settings全局定义
    REST_FRAMEWORK = {
      "DEFAULT_THROTTLE_CLASSES":["xxx.xxx.xx.限流类", ],
      "DEFAULT_THROTTLE_RATES": {
        "user": "10/m",  #与scope对应,没有值会抛出异常
        "xx":"100/h"
      }
    }'''
    THROTTLE_RATES = {"user": "10/s"}#没有定义会去全局定义里取

    def get_cache_key(self, request, view):
        if request.user:
            ident = request.user.pk  # 用户ID
        else:
            ident = self.get_ident(request)  # 获取请求用户IP(去request中找请求头)

        #throttle_user_11.11.11.11

        return self.cache_format % {'scope': self.scope, 'ident': ident}

    def throttle_failure(self):
        wait = self.wait()
        detail = {
            "code": 1005,
            "data": "访问频率限制",
            'detail': "需等待{}s才能访问".format(int(wait))
        }
        raise ThrottledException(detail)

使用限流需要使用django-redis,安装pip install django-redis

# cache缓存配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://192.168.31.125:6379/0",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100},
            'decode_responses': True,
            "PASSWORD": "xxxx",
        },
    }
}
posted @   麦兜顶当当  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示