使用django-guardian實(shí)現(xiàn)django-admin的行級(jí)權(quán)限控制的方法
用django框架來(lái)做一些后臺(tái)管理的web頁(yè)面簡(jiǎn)直太方便了,django自帶模塊級(jí)的權(quán)限系統(tǒng),用來(lái)做一些內(nèi)部的系統(tǒng)非常合適,可以大大的減少開(kāi)發(fā)量。但是django自帶的權(quán)限系統(tǒng)還不支持行級(jí)的權(quán)限控制,如果要實(shí)現(xiàn)行級(jí)的權(quán)限控制,需要依賴(lài)第三方的app來(lái)開(kāi)發(fā),或者自己重新寫(xiě)一個(gè)。
需求描述
我們項(xiàng)目組開(kāi)發(fā)的一些系統(tǒng)通常會(huì)用mysql數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)一些配置,但是如果每次有配置修改的時(shí)候都去手動(dòng)修改mysql數(shù)據(jù)的話,會(huì)挺麻煩的,同時(shí)也比較容易出錯(cuò)。django-admin能夠根據(jù)定義的model自動(dòng)的生成相應(yīng)的頁(yè)面,同時(shí)還能提供權(quán)限的管理,所以我們就把一些系統(tǒng)到的配置放到django中。但是到現(xiàn)在,隨著系統(tǒng)的需求越來(lái)越多,該系統(tǒng)已經(jīng)不止我們自己項(xiàng)目組的人員使用,也要開(kāi)放給其他項(xiàng)目組的同事使用,所以就產(chǎn)生了一些更細(xì)粒度的權(quán)限需求。因此,我們要在現(xiàn)有的系統(tǒng)上支持行級(jí)的權(quán)限控制。
解決方案
當(dāng)然可以自己寫(xiě)一套權(quán)限系統(tǒng)了,但是自己寫(xiě)的成本比較高,而且自己寫(xiě)的不一定比較好。所以我就先在網(wǎng)上找了一些現(xiàn)成的解決方案, https://djangopackages.org/grids/g/perms/ 該鏈接列出了現(xiàn)有的一些第三方的權(quán)限系統(tǒng)解決方案。從該頁(yè)面來(lái)看,django-guardian是最受歡迎的第三方權(quán)限系統(tǒng),而且支持行級(jí)的權(quán)限系統(tǒng),同時(shí)還可以整合到django-admin里面,所以我就選擇了django-guardian。
關(guān)鍵步驟
安裝配置django-guardian
安裝配置django-guardian比較簡(jiǎn)單,按照她項(xiàng)目提供的 文檔 進(jìn)行安裝就可以了,安裝完成后會(huì)在數(shù)據(jù)庫(kù)里面創(chuàng)建兩張權(quán)限相關(guān)的表。
把django-guardian整合到django-admin
首先把a(bǔ)dmin.py文件里面需要用到行級(jí)權(quán)限的類(lèi),由原來(lái)的繼承admin.ModelAdmin,改成繼承GuardedModelAdmin,這時(shí)候打開(kāi)某個(gè)數(shù)據(jù)行的頁(yè)面的時(shí)候,在該頁(yè)面的右上角的歷史旁邊會(huì)顯示編輯對(duì)象權(quán)限的按鈕,點(diǎn)擊該按鈕進(jìn)去相應(yīng)的頁(yè)面就可以編輯該行數(shù)據(jù)的具體權(quán)限。
配置完權(quán)限的時(shí)候,用一個(gè)新的用戶測(cè)試的話,會(huì)發(fā)現(xiàn)該用戶沒(méi)有權(quán)限來(lái)訪問(wèn)任何的數(shù)據(jù),這是因?yàn)镚uardedModelAdmin還有很多事情沒(méi)有幫我們做,我們還需要重寫(xiě)一些函數(shù)來(lái)實(shí)現(xiàn)admin后臺(tái)頁(yè)面的顯示。具體的信息看下面的代碼注釋。
from guardian.admin import GuardedModelAdmin from guardian.shortcuts import get_objects_for_user, assign_perm, remove_perm, get_users_with_perms, \ get_groups_with_perms # 需改前 @admin.register(DataAssistantJob) class DataAssistantJobAdmin(admin.ModelAdmin): pass # 修改后 @admin.register(DataAssistantJob) class DataAssistantJobAdmin(GuardedModelAdmin): # app是否在主頁(yè)面中顯示的話由該函數(shù)決定 def has_module_permission(self, request): if super().has_module_permission(request): return True return self.get_model_objs(request).exists() # 在顯示數(shù)據(jù)列表額時(shí)候,哪些數(shù)據(jù)顯示,哪些不顯示,由該函數(shù)控制 def get_queryset(self, request): if request.user.is_superuser: return super().get_queryset(request) data = self.get_model_objs(request) return data # 內(nèi)部用來(lái)獲取某個(gè)用戶有權(quán)限訪問(wèn)的數(shù)據(jù)行 def get_model_objs(self, request, action=None, klass=None): opts = self.opts actions = [action] if action else ['view', 'change', 'delete'] klass = klass if klass else opts.model model_name = klass._meta.model_name return get_objects_for_user(user=request.user, perms=[f'{perm}_{model_name}' for perm in actions], klass=klass, any_perm=True) # 用來(lái)判斷某個(gè)用戶是否有某個(gè)數(shù)據(jù)行的權(quán)限 def has_perm(self, request, obj, action): opts = self.opts codename = f'{action}_{opts.model_name}' if obj: return request.user.has_perm(f'{opts.app_label}.{codename}', obj) else: return self.get_model_objs(request, action).exists() # 是否有查看某個(gè)數(shù)據(jù)行的權(quán)限 def has_view_permission(self, request, obj=None): return self.has_perm(request, obj, 'view') # 是否有修改某個(gè)數(shù)據(jù)行的權(quán)限 def has_change_permission(self, request, obj=None): return self.has_perm(request, obj, 'change') # 是否有刪除某個(gè)數(shù)據(jù)行的權(quán)限 def has_delete_permission(self, request, obj=None): return self.has_perm(request, obj, 'delete') # 用戶應(yīng)該擁有他新增的數(shù)據(jù)行的所有權(quán)限 def save_model(self, request, obj, form, change): result = super().save_model(request, obj, form, change) if not request.user.is_superuser and not change: opts = self.opts actions = ['view', 'add', 'change', 'delete'] [assign_perm(f'{opts.app_label}.{action}_{opts.model_name}', request.user, obj) for action in actions] return result
通過(guò)上面的修改,django-admin中的模塊就能夠支持行級(jí)的權(quán)限,并能夠正確的在后臺(tái)頁(yè)面中顯示出來(lái),當(dāng)然如果有很多的模塊需要支持行級(jí)的權(quán)限控制,則可以把上面的這些修改寫(xiě)到一個(gè)新的類(lèi)中,然后其他想支持行級(jí)權(quán)限的模塊再?gòu)脑撃K繼承就可以了。
總結(jié)
感覺(jué)django-guardian和django-admin整合,實(shí)現(xiàn)的不是很好。如果開(kāi)發(fā)者對(duì)django內(nèi)部的代碼不怎么了解,那么用django-guardian來(lái)實(shí)現(xiàn)行級(jí)權(quán)限控制的話會(huì)挺麻煩的,個(gè)人認(rèn)為django-guardian完全可以把和django-admin的整合做到開(kāi)箱即用的效果,就像django自帶的權(quán)限系統(tǒng)一樣。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
對(duì)Python多線程讀寫(xiě)文件加鎖的實(shí)例詳解
今天小編就為大家分享一篇對(duì)Python多線程讀寫(xiě)文件加鎖的實(shí)例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01python編寫(xiě)分類(lèi)決策樹(shù)的代碼
這篇文章主要為大家詳細(xì)介紹了python編寫(xiě)分類(lèi)決策樹(shù)的代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Python實(shí)現(xiàn)的txt文件去重功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)的txt文件去重功能,涉及Python針對(duì)txt文本文件的讀寫(xiě)、字符串遍歷、判斷相關(guān)操作技巧,需要的朋友可以參考下2018-07-07Python傳統(tǒng)圖像處理之皮膚區(qū)域檢測(cè)詳解
這篇文章主要介紹了在不同情景下對(duì)傳統(tǒng)圖像進(jìn)行皮膚區(qū)域檢測(cè),文章中的代碼具有一定的參考價(jià)值,感興趣的小伙伴可以跟隨小編一起來(lái)學(xué)習(xí)學(xué)習(xí)2021-12-12Python腳本/代碼的幾種常見(jiàn)運(yùn)行方式
我們知道,python腳本或者說(shuō)python程序其實(shí)是一個(gè)包含了python代碼的文件,通過(guò)運(yùn)行python代碼,我們可以驗(yàn)證腳本/程序是否按照我們的期望執(zhí)行,在python中,有多種方式來(lái)運(yùn)行腳本或程序,取決于小伙伴們的需求,接下來(lái)小編將介紹幾種常見(jiàn)的 python 代碼運(yùn)行方式2023-10-10