drf组件之权限类使用
- 第一步:写一个类,继承BasePermission
- 第二步:重写has_permission方法
- 第三步:在方法中校验用户是否有权限( request. user就是当前登录用户)
- 第四步:如果有权限,返回True ,没有权限,返回False
- 第五步:self. message 是给前端的提示信息
- 第六步:局部使用,全局使用,局部禁用
from rest_framework. permissions import BasePermission
class UserTypePermission ( BasePermission) :
def has_permission ( self, request, view) :
if request. user. user_type == 1 :
return True
else :
return False
drf组件之频率类使用
- 第一步:写一个类:继承SimpleRateThrottle
- 第二步:重写get_cache_key,返回唯一的字符串,会以这个字符串做频率限制
- 第三步:写一个类属性scop= '自定义' ,必须要跟配置文件对象
- 第四步:配置文件中写
'DEFAULT_THROTTLE_RATES' : {
'自定义' : '3/m'
}
- 第五步:局部配置,全局配置,局部禁用
from rest_framework. throttling import BaseThrottle, SimpleRateThrottle
class MyThrottling ( SimpleRateThrottle) :
scope = 'luffy'
def get_cache_key ( self, request, view) :
return request. META. get( 'REMOTE_ADDR' )
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES' : [ 'app01.permission.UserLevelPermission' ] ,
'DEFAULT_THROTTLE_RATES' : {
'dy' : '5/m'
}
}
认证类源码分析
- 之前咱们读APIView的执行流程- - - 》包装了新的request,执行了3 大认证,执行视图类的方法,处理了全局异常
- 入口:APIView的dispatch
- APIView的dispatch的496 行上下:self. initial( request, * args, ** kwargs)
- APIView的initial
- 413 行上下:有三句话,分别是: 认证,权限,频率
self. perform_authentication( request)
self. check_permissions( request)
self. check_throttles( request)
- 读认证类的源码- - - 》APIView的perform_authentication( request) ,315 行上下
def perform_authentication ( self, request) :
request. user
- request是新的request- - - 》Request类中找user属性( 方法) ,是个方法包装成了数据属性
- 来到Request类中找:220 行
def user ( self) :
if not hasattr ( self, '_user' ) :
with wrap_attributeerrors( ) :
self. _authenticate( )
return self. _user
- Request的self. _authenticate( ) - - - 》373 行
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( )
权限类源码分析
- 先读最简单的权限执行流程- - - 》APIView的check_permissions( request) ,325 行上下
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的self. get_permissions( ) ,273 行上下
return [ permission( ) for permission in self. permission_classes]
- self. permission_classes 就是咱们在视图类中配的权限类的列表
- 所以这个get_permissions返回的是 咱们在视图类中配的权限类的对象列表[ UserTypePermession( ) , ]
- 为什么要写一个类,重写has_permission方法,有三个参数,为什么一定要return True 或False ,messgage可以做什么用
频率类源码分析(部分)
- 之前咱们读APIView的执行流程- - - 》包装了新的request,执行了3 大认证,执行视图类的方法,处理了全局异常
- 入口:APIView的dispatch
- APIView的dispatch的496 行上下:self. initial( request, * args, ** kwargs)
- APIView的initial
- 413 行上下:有三句话,分别是: 认证,权限,频率
self. perform_authentication( request)
self. check_permissions( request)
self. check_throttles( request)
- APIView的check_throttles:351 上下
def check_throttles ( self, request) :
throttle_durations = [ ]
for throttle in self. get_throttles( ) :
if not throttle. allow_request( request, self) :
throttle_durations. append( throttle. wait( ) )
- 总结:要写频率类,必须重写allow_request方法,返回True (没有到频率的限制)或False (到了频率的限制)
鸭子类型
不需要显示的继承某个类,只要我的类中有run和speak方法,我就是鸭子这个类
- 方式一:abc模块,装饰后,必须重写方法,不重写就报错
- 方式二:drf源码中使用的:父类中写这个方法,但没有具体实现,直接抛异常
自主练习
url.py
from django. contrib import admin
from django. urls import path, include
from rest_framework. routers import SimpleRouter
from app01 import views
router = SimpleRouter( )
router. register( 'user' , views. UserView, 'user' )
router. register( 'book' , views. BookView, 'book' )
router. register( 'publish' , views. PublishView, 'publish' )
urlpatterns = [
path( 'admin/' , admin. site. urls) ,
path( '' , include( router. urls) ) ,
]
models.py
from django. db import models
class User ( models. Model) :
"用户表"
username = models. CharField( max_length= 32 )
password = models. CharField( max_length= 32 )
user_level = models. IntegerField( default= 3 , choices= ( ( 1 , '超级管理员' ) , ( 2 , '普通管理员' ) , ( 3 , '普通用户' ) ) )
def __str__ ( self) :
return self. username
class UserToken ( models. Model) :
user = models. OneToOneField( to= 'User' , on_delete= models. CASCADE)
token = models. CharField( max_length= 32 , null= True )
class Book ( models. Model) :
"书籍表"
book_name = models. CharField( max_length= 32 )
book_price = models. CharField( max_length= 32 )
book_publish = models. CharField( max_length= 32 )
def __str__ ( self) :
return self. book_name
class Publish ( models. Model) :
"出版社表"
publish_name = models. CharField( max_length= 32 )
publish_address = models. CharField( max_length= 128 )
book = models. ForeignKey( to= 'Book' , on_delete= models. CASCADE)
def __str__ ( self) :
return self. publish_name
views.py
from rest_framework. viewsets import ModelViewSet, ViewSet
from . serializer import BookModelSerializer, PublishModelSerializer
from . models import User, Book, Publish, UserToken
from rest_framework. decorators import action
import uuid
from rest_framework. response import Response
from . permission import UserLevelPermission
from . auth import LoginAuth
from . throttle import MyThrottle
class BookView ( ModelViewSet) :
authentication_classes = [ LoginAuth, ]
throttle_classes = [ MyThrottle, ]
queryset = Book. objects. all ( )
serializer_class = BookModelSerializer
class PublishView ( ModelViewSet) :
authentication_classes = [ LoginAuth, ]
throttle_classes = [ MyThrottle, ]
queryset = Publish. objects. all ( )
serializer_class = PublishModelSerializer
class UserView ( ViewSet) :
authentication_classes = [ ]
permission_classes = [ ]
@action ( methods= [ 'POST' , ] , detail= False , url_path= 'login' )
def login ( self, request) :
username = request. data. get( 'username' )
password = request. data. get( 'password' )
user = User. objects. filter ( username= username, password= password) . first( )
if user:
token = str ( uuid. uuid4( ) )
UserToken. objects. update_or_create( defaults= { 'token' : token} , user= user)
return Response( { 'code' : 100 , 'msg' : '登录成功' , 'token' : token} )
else :
return Response( { 'code' : 101 , 'msg' : '用户名或密码错误' } )
serializer.py
from rest_framework import serializers
from . models import Book, Publish
class BookModelSerializer ( serializers. ModelSerializer) :
class Meta :
model = Book
fields = '__all__'
class PublishModelSerializer ( serializers. ModelSerializer) :
class Meta :
model = Publish
fields = '__all__'
auth.py
from . models import UserToken
from rest_framework. authentication import BaseAuthentication
from rest_framework. exceptions import AuthenticationFailed
"用户登录认证"
class LoginAuth ( BaseAuthentication) :
def authenticate ( self, request) :
token = request. GET. get( 'token' )
user_token = UserToken. objects. filter ( token= token) . first( )
if user_token:
return user_token. user, token
else :
raise AuthenticationFailed( '您还没有进行认证,请认证后进行登录' )
permission.py
from rest_framework. permissions import BasePermission
"用户权限校验"
class UserLevelPermission ( BasePermission) :
def has_permission ( self, request, view) :
if request. user. user_level == 1 :
return True
else :
self. message = '您是%s,您没有权限登录,请联系后台管理员进行处理!' % request. user. get_user_level_display( )
return False
throttle.py
from rest_framework. throttling import BaseThrottle, SimpleRateThrottle
class MyThrottle ( SimpleRateThrottle) :
scope = 'dy'
def get_cache_key ( self, request, view) :
return request. META. get( 'REMOTE_ADDR' )
settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES' : [ 'app01.permission.UserLevelPermission' ] ,
'DEFAULT_THROTTLE_RATES' : {
'dy' : '5/m'
}
}
测试示例
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)