權限校驗和認證校驗必須同時使用,而且權限校驗是排在認證校驗以後的,這在源碼中能夠查找到其執行順序。django
權限校驗也很重要,認證校驗能夠確保一個用戶登陸以後才能對接口作操做,而權限校驗能夠依據這個登陸用戶的類型來限定能對接口作那些操做。api
下面是模型表,對於不一樣等級的用戶,訪問同一url
,可以獲取到的電影內容也不同。app
from django.db import models # Create your models here. class User(models.Model): user_id = models.AutoField(primary_key=True) user_name = models.CharField(max_length=32) user_password = models.CharField(max_length=32) user_type = models.IntegerField(choices=( [0,"普通用戶"], [1,"黃金VIP"], [2,"鑽石VIP"], )) user_token = models.CharField(max_length=64, null=True, unique=True) class Film(models.Model): film_id = models.AutoField(primary_key=True) film_name = models.CharField(max_length=32) film_grade = models.IntegerField( choices=( [0,"免費電影"], [1,"黃金VIP專享"], [2,"鑽石VIP專享"] ) )
用戶表數據以下:源碼分析
電影表數據以下:post
採用模型類序列器,而且只對電影作序列化:測試
from rest_framework import serializers from app01 import models class FilmModelSerializers(serializers.ModelSerializer): class Meta: model = models.Film fields = "__all__"
下面是認證權限,只有登陸後的用戶才能夠看到電影信息。若是沒有登陸將不容許查看全部電影的頁面,或者你也能夠不設置認證校驗,可是在權限設置中能夠設置匿名用戶直接返回一個False也行。網站
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import APIException from app01 import models class LoginAuth(BaseAuthentication): def authenticate(self,request): token = request.META.get("HTTP_TOKEN") if not token: # 未登陸 raise APIException("未登陸,沒法查看本電影網站,請先登陸") user_obj = models.User.objects.filter(user_token=token).first() if not user_obj: raise APIException("token無效,登陸失敗") else: return user_obj,user_obj.user_type # 將用戶對象自己以及用戶的類型存儲到request.user以及request.auth中
下面是視圖的代碼:ui
from uuid import uuid4 from rest_framework.generics import ListAPIView from rest_framework.generics import GenericAPIView from rest_framework.views import APIView from rest_framework.views import Response from app01 import models from app01 import serializationClass from app01 import app01_auth class FilmAPI(ListAPIView,GenericAPIView): authentication_classes = [app01_auth.LoginAuth] # 必須登陸 queryset = models.Film.objects.all() # 默認查看全部,任何用戶都是 serializer_class = serializationClass.FilmModelSerializers def get(self,request): return self.list(request) class Login(APIView): def post(self,request): user_dict = { "user_name":request.data.get("user_name"), "user_password":request.data.get("user_password"), } user_obj = models.User.objects.filter(**user_dict).first() if not user_obj: return Response(data="用戶名或密碼錯誤") else: token = uuid4() # 建立token user_obj.user_token = token user_obj.save() return Response(data="登陸成功",headers={"token":token}) # 返回token到請求頭中
下面是路由。url
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/',views.Login.as_view()), path('api/film/',views.FilmAPI.as_view()), ]
如今咱們啓動django
項目試試。能夠發現,當咱們在請求頭中設置好token
並朝api
發送GET
請求時,它會返回全部的數據。spa
咱們登陸的是jack
這個用戶,他應該只能看到免費電影,而相似泰坦尼克號這種電影是不該該讓他看見的。
寫一個類,繼承BasePermission
,重寫has_permission()
方法,若是權限經過,就返回True
,不經過就返回False
。
接下來咱們來寫權限校驗,has_permission()
方法接受兩個參數,分別是request
和view
,也就是視圖類的實例化自己。
from rest_framework.permissions import BasePermission from app01 import models from django.db.models import Q class UserPermission(BasePermission): def has_permission(self, request, view): if request.auth == 1: # 若是是普通用戶,修改當前獲取的資源爲免費電影 view.queryset = models.Film.objects.filter(film_grade=1) elif request.auth == 2: # 若是是黃金VIP,則只能獲取黃金VIP電影和免費電影 view.queryset = models.Film.objects.filter(Q(film_grade=2) | Q(film_grade=1)) else: pass # 默認就是獲取全部,因此不用修改 return True # 權限校驗完成,設置好了。普通用戶只能看免費電影
下面是局部使用,只須要用一個變量名爲permission_classes
的列表,將權限校驗的類放入便可:
class FilmAPI(ListAPIView,GenericAPIView): authentication_classes = [app01_auth.LoginAuth] # 必須登陸 permission_classes = [app01_permissions.UserPermission] # 作權限設置 queryset = models.Film.objects.all() # 默認查看全部,任何用戶都是 serializer_class = serializationClass.FilmModelSerializers def get(self,request): return self.list(request)
若是是全局使用,則須要到項目全局文件夾下的settings.py
中進行設置:
# 全局使用 REST_FRAMEWORK={ 'DEFAULT_PERMISSION_CLASSES': [ 'app01.app01_permissions.UserPermission', ], }
若是想取消某個接口的權限認證設置,則在其中設置類屬性permission_classes
是一個空列表。
以下所示,登陸功能不須要驗證權限,咱們對他取消掉便可。
class Login(APIView): permission_classes = [] # 取消權限驗證設置 def post(self,request): user_dict = { "user_name":request.data.get("user_name"), "user_password":request.data.get("user_password"), } user_obj = models.User.objects.filter(**user_dict).first() if not user_obj: return Response(data="用戶名或密碼錯誤") else: token = uuid4() # 建立token user_obj.user_token = token user_obj.save() return Response(data="登陸成功",headers={"token":token}) # 返回token到請求頭中
再次使用jack
的token
進行登陸,能夠發現他只會看到免費電影了。
而使用ken
的token
進行登陸,他將看不到鑽石VIP的電影,如泰坦尼克號:
假若使用yunya
的token
進行登陸,則能夠查看到全部的電影。
若是你是使用auth
組件來作的一系列登陸等,則能夠使用內置權限。
它會判斷該用戶的is_staff
字段是否爲True
。
內置權限的類使用有不少,以下所示:
# 演示一下內置權限的使用:IsAdminUser,控制是否對網站後臺有權限的人 # 1 建立超級管理員 # 2 寫一個測試視圖類 from rest_framework.permissions import IsAdminUser from rest_framework.authentication import SessionAuthentication class TestView3(APIView): authentication_classes=[SessionAuthentication,] # 必須有認證 permission_classes = [IsAdminUser] # 權限設置 def get(self,request,*args,**kwargs): return Response('這是22222222測試數據,超級管理員能夠看') # 3 超級用戶登陸到admin,再訪問test3就有權限 # 4 正常的話,普通管理員,沒有權限看(判斷的是is_staff字段)
權限校驗排在認證校驗以後,這在源碼中能夠查看到。
它的源碼相比於認證的源碼來講簡單的多,認證的執行是在request.user
中進行的,而它直接是在當前視圖類中進行,因此很簡單。
# APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的對象方法) def check_permissions(self, request): # 遍歷權限對象列表獲得一個個權限對象(權限器),進行權限認證 遍歷 for (權限認證的實例化對象) for permission in self.get_permissions(): # 權限類必定有一個has_permission權限方法,用來作權限認證的 # 參數:權限對象self、請求對象request、視圖類對象 # 返回值:有權限返回True,無權限返回False if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) )