認(rèn)證&權(quán)限
認(rèn)證和權(quán)限是一起用的。
可以再配置文件中settings配置全局默認(rèn)的認(rèn)證&權(quán)限
REST_FRAMEWORK = {
# python中認(rèn)證的配置
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication', # 基本認(rèn)證
'rest_framework.authentication.SessionAuthentication', # session認(rèn)證
)
# python中權(quán)限的配置,如果沒(méi)有指明,系統(tǒng)默認(rèn)的權(quán)限是允許所有人訪問(wèn)的
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)
}
也可以在每個(gè)視圖中通過(guò)設(shè)置authentication_classess屬性來(lái)設(shè)置
從DRF框架中導(dǎo)入包authentication
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView
class ExampleView(APIView):
# 在子應(yīng)用中定義authentication_classes,可以寫(xiě)一個(gè)也可以寫(xiě)多個(gè)
# authentication_classes = (SessionAuthentication, BasicAuthentication)
# 配合權(quán)限來(lái)使用我們寫(xiě)一個(gè)。
authentication_classes = [SessionAuthentication]
提供的權(quán)限
1.AllowAny 允許所有用戶
2.IsAuthenticated 僅通過(guò)認(rèn)證的用戶
3.IsAdminUser 僅管理員用戶
4.IsAuthenticatedOrReadOnly 認(rèn)證的用戶可以完全操作,否則只能get讀取
自定義權(quán)限
如需自定義權(quán)限,需繼承rest_framework.permissions.BasePermission父類(lèi),并實(shí)現(xiàn)以下兩個(gè)任何一個(gè)方法或全部
.has_permission(self, request, view)
是否可以訪問(wèn)視圖, view表示當(dāng)前視圖對(duì)象,如果沒(méi)有設(shè)置的話默認(rèn)的是True,如果設(shè)置
False則表示所有的用戶都不能訪問(wèn)該視圖
.has_object_permission(self, request, view, obj)
是否可以訪問(wèn)數(shù)據(jù)對(duì)象, view表示當(dāng)前視圖, obj為數(shù)據(jù)對(duì)象,控制視圖能夠訪問(wèn)添加了權(quán)限控制類(lèi)的數(shù)據(jù)對(duì)象
class MyPermission(BasePermission):
def has_permission(self, request, view)
"""讓所有用戶都有權(quán)限"""
return True
def has_object_permission(self, request, view, obj):
"""用戶是否有權(quán)限訪問(wèn)添加了權(quán)限控制類(lèi)的數(shù)據(jù)對(duì)象"""
# 需求:用戶能夠訪問(wèn)id為1,3的對(duì)象,其他的不能夠訪問(wèn)
if obj.id in (1, 3):
return True
else:
return False
class BookInfoViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
# 表示登錄有權(quán)限
permission_classes = [IsAuthenticated]
# 表示所有用戶都有權(quán)限,只能夠訪問(wèn)id 為1,3的數(shù)據(jù)
permission_classes = [MyPermission]
節(jié)流
源碼流程
和認(rèn)證的流程一樣,進(jìn)入initial(request)
其中check_throttles(request)是節(jié)流的函數(shù)
VisitThrottle自定義權(quán)限類(lèi)
allow_request()返回值:
True, 允許訪問(wèn)
False, 訪問(wèn)太頻繁
wait()返回值:
返回一個(gè)整數(shù),表示下次還有多久可以訪問(wèn)
使用自定義類(lèi)
class VisitThrottle(BaseThrottle):
def __init__(self):
self.history = []
def allow_request(self, request, view):
remote_addr = request.META.get('REMOTE_ADDR')
ctime = time.time()
if remote_addr not in VISIT_RECORD:
print("沒(méi)有此IP")
VISIT_RECORD[remote_addr] = [ctime, ]
return True
history = VISIT_RECORD.get(remote_addr)
print(history)
while history and history[-1] < ctime-8:
history.pop()
self.history = history
if len(history) < 3:
history.insert(0, ctime)
return True
def wait(self):
ctime = time.time()
return 8-(ctime-self.history[-1])
在定義的類(lèi)中復(fù)寫(xiě)allow_request方法,返回True或者False表示可以訪問(wèn)或者訪問(wèn)頻率太高
引入
settings.py
DEFAULT_THROTTLE_CLASSES': ['apps.api.utils.throttle.UserThrottle'],
#2.局部
class AuthView(APIView):
用于用戶登錄認(rèn)證
throttle_classes = [VisitThrottle,]
自定義類(lèi)繼承內(nèi)置類(lèi)
# throttle.py
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope = "Vistor"
def get_cache_key(self, request, view):
return self.get_ident(request)
class UserThrottle(SimpleRateThrottle):
scope = "User"
def get_cache_key(self, request, view):
return self.user.username
scope從settings.py中尋找DEFAULT_THROTTLE_RATES字典的Key,就是訪問(wèn)頻率限制,scope可以區(qū)分不同的函數(shù)的不同限制;get_cache_key(self, request, view)返回一個(gè)唯一標(biāo)示用以區(qū)分不同的用戶,對(duì)于匿名用戶返回IP保存到緩存中限制訪問(wèn),對(duì)于注冊(cè)的用戶取用戶名(唯一)來(lái)區(qū)分就可以。
settings.py
'DEFAULT_THROTTLE_RATES': {
'Vistor': '3/m',
'User': '10/m'
},
版本
源碼流程
1.和認(rèn)證的流程一樣,進(jìn)入initial(request)
在認(rèn)證,權(quán)限,節(jié)流前先執(zhí)行了這兩句函數(shù),獲取到version,scheme,并分別賦值給request對(duì)象的version, versioning_scheme屬性
獲取版本(version)和scheme
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
進(jìn)入determine_version()函數(shù)
scheme = self.versioning_class()
return (scheme.determine_version(request, *args, **kwargs), scheme)
在這里獲取到scheme就是api_settings.DEFAULT_VERSIONING_CLASS,系統(tǒng)默認(rèn)版本控制類(lèi),那scheme.determine_version(request, *args, kwargs) 就是該類(lèi)下的一個(gè)方法
查看rest_framework庫(kù)的一個(gè)自帶類(lèi)中的determine_version方法
class QueryParameterVersioning(BaseVersioning):
"""
GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
"""
invalid_version_message = _('Invalid version in query parameter.')
def determine_version(self, request, *args, **kwargs):
version = request.query_params.get(self.version_param, self.default_version)
if not self.is_allowed_version(version):
raise exceptions.NotFound(self.invalid_version_message)
return version
返回的是版本號(hào)。于是version, scheme分別是版本號(hào)和一個(gè)版本控制類(lèi),并分別賦值給request對(duì)象的version, versioning_scheme屬性。
使用
內(nèi)置類(lèi)的使用
1.放到url后作為get參數(shù)
http://127.0.0.1:8000/api/users/?version=v1
from rest_framework.versioning import QueryParameterVersioning
class UsersView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
# 獲取版本
self.dispatch
print(request.version)
# 獲取版本處理對(duì)象
# print(request.versioning_scheme)
# u1 = request.versioning_scheme.reverse('api:uuu', request=request)
# print("u1:", u1)
# u2 = reverse('api:uuu', kwargs={'version': 1})
# print("u2:", u2)
return HttpResponse('用戶列表')
2.用正則匹配
re_path(r'^(?P<version>[v1|v2]+)/users/', views.UsersView.as_view(), name="uuu"),
from rest_framework.versioning import URLPathVersioning
class UsersView(APIView):
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
# 獲取版本
self.dispatch
print(request.version)
# 獲取版本處理對(duì)象
# print(request.versioning_scheme)
# u1 = request.versioning_scheme.reverse('api:uuu', request=request)
# print("u1:", u1)
# u2 = reverse('api:uuu', kwargs={'version': 1})
# print("u2:", u2)
return HttpResponse('用戶列表')
request.versioning_scheme.reverse方法可以獲取路由,是drf中的方法
django.urls.reverse 是django中的反向獲取路由方法
u1: http://127.0.0.1:8000/api/v1/users/
u2: /api/1/users/
解析器
1.本質(zhì)
· 請(qǐng)求頭
· 狀態(tài)嗎
· 請(qǐng)求方法
2.源碼流程
· dispatch : request封裝
· request.data