国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Django中內置權限擴展的示例分析

發(fā)布時(shí)間:2021-09-04 11:55 來(lái)源:億速云 閱讀:0 作者:小新 欄目: 開(kāi)發(fā)技術(shù)

這篇文章將為大家詳細講解有關(guān)Django中內置權限擴展的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

背景介紹

overmind項目使用了Django內置的權限系統,Django內置權限系統基于model層做控制,新的model創(chuàng )建后會(huì )默認新建三個(gè)權限,分別為:add、change、delete,如果給用戶(hù)或組賦予delete的權限,那么用戶(hù)將可以刪除這個(gè)model下的所有數據。

原本overmind只管理了我們自己部門(mén)的數據庫,權限設置只針對具體的功能不針對細粒度的數據庫實(shí)例,例如用戶(hù)A 有審核的權限,那么用戶(hù)A 可以審核所有的DB,此時(shí)使用內置的權限系統就可以滿(mǎn)足需求了,但隨著(zhù)系統的不斷完善要接入其他部門(mén)的數據庫管理,這就要求針對不同用戶(hù)開(kāi)放不同DB的權限了,例如A部門(mén)的用戶(hù)只能操作A部門(mén)的DB,Django內置基于model的權限無(wú)法滿(mǎn)足需求了。

實(shí)現過(guò)程

先來(lái)確定下需求:

1.  保持原本的基于功能的權限控制不變,例如用戶(hù)A有查詢(xún)權限,B有審核權限

2.  增加針對DB實(shí)例的權限控制,例如用戶(hù)A只能查詢(xún)特定的DB,B只能審核特定的DB

對于上邊需求1用內置的權限系統已經(jīng)可以實(shí)現,這里不贅述,重點(diǎn)看下需求2,DB信息都存放在同一個(gè)表里,不同用戶(hù)能操作不同的DB,也就是需要把每一條DB信息與有權限操作的用戶(hù)進(jìn)行關(guān)聯(lián),為了方便操作,我們考慮把DB跟用戶(hù)組關(guān)聯(lián),在用戶(hù)組里的用戶(hù)都有權限,而操作類(lèi)型經(jīng)過(guò)分析主要有兩類(lèi)讀和寫(xiě),那么需要給每個(gè)實(shí)例添加兩個(gè)字段分別記錄對此實(shí)例有讀和寫(xiě)權限的用戶(hù)組

如下代碼在原來(lái)的model基礎上添加 read_groupswrite_groups 字段,DB實(shí)例跟用戶(hù)組應是ManyToManyField多對多關(guān)系,一個(gè)實(shí)例可以關(guān)聯(lián)多個(gè)用戶(hù)組,一個(gè)用戶(hù)組也可以屬于多個(gè)實(shí)例

class Mysql(models.Model):
 Env = (
 (1, 'Dev'),
 (2, 'Qa'),
 (3, 'Prod'),
 )
 create_time = models.DateTimeField(auto_now_add=True, verbose_name='創(chuàng  )建時(shí)間')
 update_time = models.DateTimeField(auto_now=True, verbose_name='更新時(shí)間')

 project_id = models.IntegerField(verbose_name='項目')
 project_tmp = models.CharField(max_length=128, default='')
 environment = models.IntegerField(choices=Env, verbose_name='環(huán)境')

 master_host = models.GenericIPAddressField(verbose_name='master主機')
 master_port = models.IntegerField(default=3306, verbose_name='master端口')

 slave_host = models.GenericIPAddressField(null=True, verbose_name='slave主機')
 slave_port = models.IntegerField(null=True, default=3306, verbose_name='slave端口')

 database = models.CharField(max_length=64, verbose_name='數據庫')

 read_groups = models.ManyToManyField(Group, related_name='read', verbose_name='讀權限')
 write_groups = models.ManyToManyField(Group, related_name='write', verbose_name='寫(xiě)權限')

 description = models.TextField(null=True, verbose_name='備注')

model確定了,接下來(lái)我們分三部分詳細介紹下權限驗證的具體實(shí)現

列表頁(yè)權限控制

如上圖列表頁(yè),每個(gè)用戶(hù)進(jìn)入系統后只能查看自己有讀權限的MySQL實(shí)例列表,管理員能查看所有,代碼如下:

def mysql(request):
 if request.method == 'GET':
 if request.user.is_superuser:
 _lists = Mysql.objects.all().order_by('id')
 else:
 # 獲取登錄用戶(hù)的所有組
 _user_groups = request.user.groups.all()

 # 構造一個(gè)空的QuerySet然后合并
 _lists = Mysql.objects.none()
 for group in _user_groups:
 _lists = _lists | group.read.all()

 return render(request, 'overmind/mysql.index.html', {'request': request, 'lPage': _lists})

實(shí)現的思路是:獲取登錄用戶(hù)的所有組,然后循環(huán)查詢(xún)每個(gè)組有讀取權限的數據庫實(shí)例,最后把每個(gè)組有權限讀的數據庫實(shí)例進(jìn)行合并返回

獲取登錄用戶(hù)的所有組用到了ManyToMany的查詢(xún)方法: request.user.groups.all()

最終返回的一個(gè)結果是QuerySet,所以我們需要先構造一個(gè)空的Queryset: Mysql.objects.none()

QuerySet合并不能用簡(jiǎn)單的相加,應為: QuerySet-1 | QuerySet-2

查詢(xún)接口權限控制

如上圖系統中有很多功能是需要根據項目、環(huán)境查詢(xún)對應的DB信息的,對于此類(lèi)接口也需要控制用戶(hù)只能查詢(xún)自己有權限讀的DB實(shí)例,管理員能查看所有,代碼如下:

def get_project_database(request, project, environment):
 if request.method == 'GET':
 _jsondata = {}

 if request.user.is_superuser:
 # 返回所有項目和環(huán)境匹配的DB
 _lists = Mysql.objects.filter(
 project_id=int(project),
 environment=int(environment)
 )

 _jsondata = {i.id: i.database for i in _lists}
 else:
 # 只返回用戶(hù)有權限查詢(xún)的DB
 _user_groups = request.user.groups.all()

 for group in _user_groups:
 # 循環(huán)mysql表中有read_groups權限的所有組
 for mysql in group.read.all():
  if mysql.project_id == int(project) and mysql.environment == int(environment):
  _jsondata[mysql.id] = mysql.database

 return JsonResponse(_jsondata)

實(shí)現思路與上邊類(lèi)似,只是多了一步根據項目和環(huán)境再進(jìn)行判斷

需要根據group去反查都有哪些DB實(shí)例包含了該組,這里用到了M2M的related_name屬性: group.read.all()

更多關(guān)于Django ORM查詢(xún)的內容可以看這篇文章 Django model select的各種用法詳解 有詳細的總結

執行操作權限控制

除了上邊的兩個(gè)場(chǎng)景之外我們還需要在執行具體的操作之前去判斷是否有權限,例如執行審核操作前判斷用戶(hù)是否對此DB有寫(xiě)權限

有很多地方都需要做這個(gè)判斷,所以把這個(gè)權限判斷單獨寫(xiě)個(gè)方法來(lái)處理,代碼如下:

def check_permission(perm, mysql, user):
 # 如果用戶(hù)是超級管理員則有權限
 if user.is_superuser:
 return True

 # 取出用戶(hù)所屬的所有組
 _user_groups = user.groups.all()

 # 取出Mysql對應權限的所有組
 if perm == 'read':
 _mysql_groups = mysql.read_groups.all()
 if perm == 'write':
 _mysql_groups = mysql.write_groups.all()

 # 用戶(hù)組和DB權限組取交集,有則表示有權限,否則沒(méi)有權限
 group_list = list(set(_user_groups).intersection(set(_mysql_groups)))

 return False if len(group_list) == 0 else True

實(shí)現思路是:根據傳入的第三個(gè)用戶(hù)參數,來(lái)獲取到用戶(hù)所有的組,然后根據傳入的第一個(gè)參數類(lèi)型讀取或寫(xiě)入和第二個(gè)參數DB實(shí)例來(lái)獲取到有權限的所有組,然后對兩個(gè)組取交集,交集不為空則表示有權限,為空則沒(méi)有

M2M的 .all() 取出來(lái)的結果是個(gè)list,兩個(gè)list取交集的方法為: list(set(list-A).intersection(set(list-B)))

view中使用就很簡(jiǎn)單了,如下:

def query(request):
 if request.method == 'POST':
 postdata = request.body.decode('utf-8')
 _host = get_object_or_404(Mysql, id=int(postdata.get('database')))

 # 檢查用戶(hù)是否有DB的查詢(xún)權限
 if check_permission('read', _host, request.user) == False:
 return JsonResponse({'state': 0, 'message': '當前用戶(hù)沒(méi)有查詢(xún)此DB的權限'})

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

成全视频在线观看在线播放高清| 野花日本大全免费观看直播| 永久免费AV无码网站在线 | 无码人妻一区二区三区兔费| 无码囯产精品一区二区免费| 美日欧激情AV大片免费观看|