drf之認證權限頻率


為了方便接下來的學習,我們創建一個新的子應用 opt

1
python manage.py startapp opt

因為接下來的功能中需要使用到登陸功能,所以我們使用django內置admin站點並創建一個管理員.

1
2
3
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py createsuperuser

1557276390641

創建管理員以后,訪問admin站點,先修改站點的語言配置

settings.py

1
2
3
4
5
6
7
8
9
LANGUAGE_CODE = 'zh-hans' # 中文

TIME_ZONE = 'Asia/Shanghai' # 時區是亞洲上海

USE_I18N = True # 國際化

USE_L10N = True # 本地化

USE_TZ = True # 數據庫是否使用TIME_ZONE,True表示使用上海的時區,False表示不使用,使用UTC時間,然后轉成上海,會差8個小時

1553043081445

訪問admin 站點效果:

1553043054133

一 認證Authentication

1.1 自定義認證方案

1.1.1 編寫models

1
2
3
4
5
6
7
8
9
# models.py
classUser(models.Model):
username=models.CharField(max_length=32)
password=models.CharField(max_length=32)
user_type=models.IntegerField(choices=((1,'超級用戶'),(2,'普通用戶'),(3,'二筆用戶')))

classUserToken(models.Model):
user=models.OneToOneField(to='User')
token=models.CharField(max_length=64)

1.1.2 新建認證類

1
2
3
4
5
6
7
8
9
10
11
from rest_framework.authentication import BaseAuthentication
class TokenAuth():
defauthenticate(self, request):
token = request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if token_obj:
return
else:
raise AuthenticationFailed('認證失敗')
defauthenticate_header(self,request):
pass

1.1.3 編寫視圖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
defget_random(name):
import hashlib
import time
md=hashlib.md5()
md.update(bytes(str(time.time()),encoding='utf-8'))
md.update(bytes(name,encoding='utf-8'))
return md.hexdigest()
classLogin(APIView):
defpost(self,reuquest):
back_msg={'status':1001,'msg':None}
try:
name=reuquest.data.get('name')
pwd=reuquest.data.get('pwd')
user=models.User.objects.filter(username=name,password=pwd).first()
if user:
token=get_random(name)
models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
back_msg['status']='1000'
back_msg['msg']='登錄成功'
back_msg['token']=token
else:
back_msg['msg'] = '用戶名或密碼錯誤'
except Exception as e:
back_msg['msg']=str(e)
return Response(back_msg)



classCourse(APIView):
authentication_classes = [TokenAuth, ]

defget(self, request):
return HttpResponse('get')

defpost(self, request):
return HttpResponse('post')

1.1.4 全局使用

1
2
3
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
}

1.1.5 局部使用

1
2
#局部使用,只需要在視圖類里加入:
authentication_classes = [TokenAuth, ]

1.2 內置認證方案(需要配合權限使用)

可以在配置文件中配置全局默認的認證方案

1
2
3
4
5
6
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication', # session認證
'rest_framework.authentication.BasicAuthentication', # 基本認證
)
}

也可以在每個視圖中通過設置authentication_classess屬性來設置

1
2
3
4
5
6
7
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
# 類屬性
authentication_classes = [SessionAuthentication, BasicAuthentication]
...

認證失敗會有兩種可能的返回值:

  • 401 Unauthorized 未認證
  • 403 Permission Denied 權限被禁止

二 權限Permissions

權限控制可以限制用戶對於視圖的訪問和對於具體數據對象的訪問。

  • 在執行視圖的dispatch()方法前,會先進行視圖訪問權限的判斷
  • 在通過get_object()獲取具體對象時,會進行模型對象訪問權限的判斷

2.1 自定義權限

2.1.1 編寫權限類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 限制只有超級用戶能訪問
from rest_framework.permissions import BasePermission
classUserPermission(BasePermission):
message = '不是超級用戶,查看不了'
defhas_permission(self, request, view):
# user_type = request.user.get_user_type_display()
# if user_type == '超級用戶':
# 權限在認證之后,所以能取到user
user_type = request.user.user_type
print(user_type)
if user_type == 1:
returnTrue
else:
returnFalse

2.1.2 全局使用

1
2
3
4
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}

2.1.3 局部使用

1
2
# 局部使用只需要在視圖類里加入:
permission_classes = [UserPermission,]

2.1.4 說明

1
2
3
4
5
6
7

如需自定義權限,需繼承rest_framework.permissions.BasePermission父類,並實現以下兩個任何一個方法或全部
- `.has_permission(self, request, view)`
是否可以訪問視圖, view表示當前視圖對象

- `.has_object_permission(self, request, view, obj)`
是否可以訪問數據對象, view表示當前視圖, obj為數據對象

2.2 內置權限

2.2.1 內置權限類

1
2
3
4
5
from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly
- AllowAny 允許所有用戶
- IsAuthenticated 僅通過認證的用戶
- IsAdminUser 僅管理員用戶
- IsAuthenticatedOrReadOnly 已經登陸認證的用戶可以對數據進行增刪改操作,沒有登陸認證的只能查看數據。

2.2.2 全局使用

可以在配置文件中全局設置默認的權限管理類,如

1
2
3
4
5
6
7
REST_FRAMEWORK = {
....

'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}

如果未指明,則采用如下默認配置

1
2
3
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)

2.2.3 局部使用

也可以在具體的視圖中通過permission_classes屬性來設置,如

1
2
3
4
5
6
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
permission_classes = (IsAuthenticated,)
...

2.2.4 實際操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 創建超級用戶,登陸到admin,創建普通用戶(注意設置職員狀態,也就是能登陸)
# 全局配置IsAuthenticated
# setting.py
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
# urls.py
path('test/', views.TestView.as_view()),
# views.py
classTestView(APIView):
defget(self,request):
return Response({'msg':'個人中心'})
# 登陸到admin后台后,直接訪問可以,如果沒登陸,不能訪問

##注意:如果全局配置了
rest_framework.permissions.IsAdminUser
# 就只有管理員能訪問,普通用戶訪問不了

三 限流Throttling

可以對接口訪問的頻次進行限制,以減輕服務器壓力。

一般用於付費購買次數,投票等場景使用.

3.1 自定義頻率類

3.1.1 編寫頻率類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 自定義的邏輯
#(1)取出訪問者ip
#(2)判斷當前ip不在訪問字典里,添加進去,並且直接返回True,表示第一次訪問,在字典里,繼續往下走
#(3)循環判斷當前ip的列表,有值,並且當前時間減去列表的最后一個時間大於60s,把這種數據pop掉,這樣列表中只有60s以內的訪問時間,
#(4)判斷,當列表小於3,說明一分鍾以內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利通過
#(5)當大於等於3,說明一分鍾內訪問超過三次,返回False驗證失敗
classMyThrottles():
VISIT_RECORD = {}
def__init__(self):
self.history=None
defallow_request(self,request, view):
#(1)取出訪問者ip
# print(request.META)
ip=request.META.get('REMOTE_ADDR')
import time
ctime=time.time()
# (2)判斷當前ip不在訪問字典里,添加進去,並且直接返回True,表示第一次訪問
if ip notin self.VISIT_RECORD:
self.VISIT_RECORD[ip]=[ctime,]
returnTrue
self.history=self.VISIT_RECORD.get(ip)
# (3)循環判斷當前ip的列表,有值,並且當前時間減去列表的最后一個時間大於60s,把這種數據pop掉,這樣列表中只有60s以內的訪問時間,
while self.history and ctime-self.history[-1]>60:
self.history.pop()
# (4)判斷,當列表小於3,說明一分鍾以內訪問不足三次,把當前時間插入到列表第一個位置,返回True,順利通過
# (5)當大於等於3,說明一分鍾內訪問超過三次,返回False驗證失敗
if len(self.history)<3:
self.history.insert(0,ctime)
returnTrue
else:
returnFalse
defwait(self):
import time
ctime=time.time()
return60-(ctime-self.history[-1])

3.1.2 全局使用

1
2
3
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES':['app01.utils.MyThrottles',],
}

3.1.3 局部使用

1
2
#在視圖類里使用
throttle_classes = [MyThrottles,]

3.2 內置頻率類

3.2.1 根據用戶ip限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#寫一個類,繼承自SimpleRateThrottle,(根據ip限制)
from rest_framework.throttling import SimpleRateThrottle
classVisitThrottle(SimpleRateThrottle):
scope = 'luffy'
defget_cache_key(self, request, view):
return self.get_ident(request)
#在setting里配置:(一分鍾訪問三次)
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES':{
'luffy':'3/m'# key要跟類中的scop對應
}
}

# 可以全局使用,局部使用

了解:錯誤信息中文顯示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
classCourse(APIView):
authentication_classes = [TokenAuth, ]
permission_classes = [UserPermission, ]
throttle_classes = [MyThrottles,]

defget(self, request):
return HttpResponse('get')

defpost(self, request):
return HttpResponse('post')
defthrottled(self, request, wait):
from rest_framework.exceptions import Throttled
classMyThrottled(Throttled):
default_detail = '傻逼啊'
extra_detail_singular = '還有 {wait} second.'
extra_detail_plural = '出了 {wait} seconds.'
raise MyThrottled(wait)

3.2.2 限制匿名用戶每分鍾訪問3次

1
2
3
4
5
6
7
8
9
10
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'anon': '3/m',
}
}
# 使用 `second`, `minute`, `hour` 或`day`來指明周期。
# 可以全局使用,局部使用

3.2.3 限制登陸用戶每分鍾訪問10次

1
2
3
4
5
6
7
8
9
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'user': '10/m'
}
}
# 可以全局使用,局部使用

3.2.4 其他

1) AnonRateThrottle

限制所有匿名未認證用戶,使用IP區分用戶。

使用DEFAULT_THROTTLE_RATES['anon'] 來設置頻次

2)UserRateThrottle

限制認證用戶,使用User id 來區分。

使用DEFAULT_THROTTLE_RATES['user'] 來設置頻次

3)ScopedRateThrottle

限制用戶對於每個視圖的訪問頻次,使用ip或user id。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
classContactListView(APIView):
throttle_scope = 'contacts'
...

class ContactDetailView(APIView):
throttle_scope = 'contacts'
...

class UploadView(APIView):
throttle_scope = 'uploads'
...
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'contacts': '1000/day',
'uploads': '20/day'
}
}

實例

全局配置中設置訪問頻率

1
2
3
4
'DEFAULT_THROTTLE_RATES': {
'anon': '3/minute',
'user': '10/minute'
}
1
2
3
4
5
6
7
8
9
10
11
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

class StudentAPIView(RetrieveAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
throttle_classes = (UserRateThrottle,)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM