在閱讀本文以前請先參考django rest framework 之 認證中關於django rest framework
的相關內容及實例html
爲了更好的管理各個功能組件,在django rest framework 之 認證中咱們說到能夠將認證類單獨的拿出來,放到其餘目錄下,而後導入到views.py
文件中,在權限環節咱們亦能夠這麼作,目錄結構就變成這樣sql
在api這個app下建立一個utils包專門用來存放相關的組件。數據庫
咱們在models.py中定義了兩個模型類,分別是django
from django.db import models class UserInfo(models.Model): USER_TYPE = ( (1,'普通用戶'), (2,'VIP'), (3,'SVIP') ) user_type = models.IntegerField(choices=USER_TYPE, default=1) username = models.CharField(max_length=32) password = models.CharField(max_length=64) class UserToken(models.Model): user = models.OneToOneField(UserInfo,on_delete=models.CASCADE) token = models.CharField(max_length=64)
在UserInfo
中經過爲用戶添加一個user_type
字段來保證用戶的身份,是普通用戶,VIP仍是SVIP,這樣就能夠經過用戶的身份驗證不一樣的權限。若是想要定義一個視圖類,這個類中的邏輯只有超級用戶才能訪問。json
能夠再utils中的permissions.py
中這麼寫api
# utils/permission.py class SVIPPremission(object): message = "必須是SVIP才能訪問" # 這裏的message表示若是不經過權限的時候,錯誤提示信息 def has_permission(self,request,view): if request.user.user_type != 3: return False return True class MyPremission(object): # 這個權限類表示當用戶爲SVIP時不可經過 def has_permission(self,request,view): if request.user.user_type == 3: return False return True
這裏只是判斷用戶的USER_TYPE
的字段,判斷用戶是否有權限,也能夠添加其餘的邏輯進行判斷。瀏覽器
在上一節的django rest framework 之 認證的認證中,將認證類放到了settings.py
文件中,這樣會做用到視圖中的每個視圖類,若是視圖類想要本身進行認證,只須要重寫authentication_classes
便可,那麼對於權限來講咱們也能夠這麼作,app
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.authenticate.FirstAuthenticate', 'api.utils.authenticate.MyAuthenticate'], "UNAUTHENTICATED_USER": None, # 匿名,request.user = None "UNAUTHENTICATED_TOKEN": None,# 匿名,request.auth = None "DEFAULT_PERMISSION_CLASSES": ['api.utils.permission.MyPermission'], # 表示每個視圖類(只要不重寫permission_classes屬性),都須要SVIP的用戶才能訪問。 }
在視圖view.py
中定義一個用戶詳情類UserInfoView
做爲測試,這裏的視圖和上一節的django rest framework 之 認證是相接的。源碼分析
from django.shortcuts import render, HttpResponse from django.http import JsonResponse from django.views import View from rest_framework.views import APIView from rest_framework.request import Request from .utils import authenticate, permission from api import models import json def md5(user): import hashlib import time # 當前時間,至關於生成一個隨機的字符串 ctime = str(time.time()) # token加密 m = hashlib.md5(bytes(user, encoding='utf-8')) m.update(bytes(ctime, encoding='utf-8')) return m.hexdigest() class AuthView(APIView): '''用於用戶登陸驗證''' authentication_classes = [] #裏面爲空,表明不須要認證 permission_classes = [] #不裏面爲空,表明不須要權限 def get(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': 'success', 'name': '偷偷'} ret = json.dumps(ret, ensure_ascii=False) return HttpResponse(ret) def post(self,request,*args,**kwargs): ret = {'code':1000,'msg':None} try: user = request.POST.get('username') pwd = request.POST.get('password') print(user, pwd) obj = models.UserInfo.objects.filter(username=user,password=pwd).first() print(obj.username, obj.password) if not obj: ret['code'] = 1001 ret['msg'] = '用戶名或密碼錯誤' #爲用戶建立token token = md5(user) #存在就更新,不存在就建立 models.UserToken.objects.update_or_create(user=obj,defaults={'token':token}) ret['token'] = token except Exception as e: ret['code'] = 1002 ret['msg'] = '請求異常' return JsonResponse(ret) ORDER_DICT = { 1:{ 'name':'apple', 'price':15 }, 2:{ 'name':'狗子', 'price':100 } } class OrderView(APIView): # 用戶想要獲取訂單,就要先經過身份認證、在全局settings.py 中已經配置 permission_classes = [] def get(self, request, *args, **kwargs): ret = { 'code': 1024, 'msg': '訂單獲取成功', } try: ret['data'] = ORDER_DICT except Exception as e: pass return JsonResponse(ret) class UserInfoView(APIView): permission_classes = [permission.SVIPPermission] def get(self, request, *args, **kwargs): print(request.user) return HttpResponse('SVIP用戶信息')
這裏的UserInfoView
重寫了permission_classes
屬性,則不會再使用settings.py
中關於認證類的配置。表示只有SVIP才能訪問這個類的內部。post
在url.py中設置路由分發
from django.conf.urls import url from api.views import AuthView, OrderView, UserInfoView urlpatterns = [ url(r'^api/v1/auth/$', AuthView.as_view()), url(r'^api/v1/order/$', OrderView.as_view()), url(r'^api/v1/info/$', UserInfoView.as_view()), ]
Postman或者瀏覽器發送請求,因爲咱們在setting.py
中配置了 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.authenticate.FirstAuthenticate', 'api.utils.authenticate.MyAuthenticate'],
會對請求進行認證,因此要帶這用戶的token
才能經過,進入到權限組件。
進入sqlite數據庫,找到對應的註冊用戶
在數據庫中,拿到刷新的用戶的最近一次的token
拿到這個token發送請求
請求成功,則說明權限生效,也能夠在將UserInfoView
改爲以下
class UserInfoView(APIView): permission_classes = [permission.SVIPPermission] def get(self, request, *args, **kwargs): print(request.user) return HttpResponse('SVIP用戶信息')
在發送請求,就會發現用戶不會有權限的提示信息。以下
像django rest framework 之 認證同樣進入,request
的請求流程,進入源碼查看具體權限的操做
在這裏能夠看到和認證中有相似的操做,獲取全部的權限類,而且執行每個權限類的has_permission()
方法,而這個方法具體封裝了咱們的判斷權限操做,可是has_permission()
方法的返回值須要時False
或者True
, self.permission_denied(request, message=getattr(permission, 'message', None))
說明能夠在權限類中重寫message
屬性,來定義權限不經過時候的提示信息。
進入self.get_permissions()
來看一下
在APIView中有定義默認的權限類,所以也能夠經過全局配置的方法配置權限類。
像認證那樣,django rest framework
中也有權限類
能夠根據本身的須要調用。
權限其實的流程跟以前的認證流程是同樣的,認證類封裝到request
中,而後再調用認證類的方法,不過這裏的方法返回值再也不是像認證組件那樣的直接返回一個認證的對象,而是返回一個True
或者False
值表示認證過的對象是否有某些權限再進行具體操做。
這裏注意的是,在本身重寫權限類的相關方法,添加本身的邏輯的時候,返回值須要是一個布爾值,Flase
或者True
,表示是否有權限。也能夠經過全局配置和局部配置權限類。