為了方便接下來的學習,我們創建一個新的子應用 opt
1
|
python manage.py startapp opt
|
因為接下來的功能中需要使用到登陸功能,所以我們使用django內置admin站點並創建一個管理員.
1 2 3
|
python3 manage.py makemigrations python3 manage.py migrate python3 manage.py createsuperuser
|

創建管理員以后,訪問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個小時
|

訪問admin 站點效果:

一 認證Authentication
1.1 自定義認證方案
1.1.1 編寫models
1 2 3 4 5 6 7 8 9
|
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', '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):
|
認證失敗會有兩種可能的返回值:
- 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.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
|
|
三 限流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
|
classMyThrottles(): VISIT_RECORD = {} def__init__(self): self.history=None defallow_request(self,request, view):
ip=request.META.get('REMOTE_ADDR') import time ctime=time.time()
if ip notin self.VISIT_RECORD: self.VISIT_RECORD[ip]=[ctime,] returnTrue self.history=self.VISIT_RECORD.get(ip)
while self.history and ctime-self.history[-1]>60: self.history.pop()
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
|
from rest_framework.throttling import SimpleRateThrottle classVisitThrottle(SimpleRateThrottle): scope = 'luffy' defget_cache_key(self, request, view): return self.get_ident(request)
|
了解:錯誤信息中文顯示
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', } }
|
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,)
|