Django之權限(起步)


一. 權限概述

1. 認識權限

為什么要有權限? 因為權限讓不同的用戶擁有不同的功能. 權限可以對功能進行划分.

生活中處處有權限. 比如, 騰訊視頻會員才有觀看某個最新電影的權限, 你有房間鑰匙就有了進入這個房間的權限. 同樣, 程序開發過程中也有權限, 我們今天所說的權限指的是web網站權限, 對於不同用戶訪問web服務時應該有不同的功能. 例如: 一個公司有CEO, 銷售主管, 銷售等等, 不同的用戶能訪問的服務也不是完全相同的. 處於這樣的需求下, 我們就需要權限控制了.

2. 為什么要開發權限組件?

組件可以減少代碼的重復, 能提高我們的開發效率--開發一次組件, 那么在以后的項目中可以一直使用.

3. web開發中權限是指什么?

首先我們要認識到, web程序是通過 url 的切換來查看不同的頁面(功能)的, 所以權限指的其實就是一個含有正則表達式的URL, 對url控制就是對權限的控制.

結論: 一個人有多少權限就取決於他有多少個URL的訪問權限.

二. 權限表結構設計

1.版本一

按照生活中的實際情況來看, 一個用戶有多個權限, 一個權限也可以分配給多個用戶, 所以我們可以設計出下面的三張表:

分析: 設計完該表結構之后, 我們又考慮到這種情況: 如果我們再新增10個用戶, 每個用戶都有權限表中的2個權限, 這意味着我們就要在"權限和用戶關聯表"中新增40條記錄. 如果再拓展到我們的實際生活中, 又會出現怎樣的情況呢? 生活中一個web網站肯定不止2個url, 這就意味着每新增一個客戶, 我們就要在某些表中增加若干條記錄. 這樣做不僅加重的程序員工作任務, 而且造成了數據庫空間的嚴重浪費. 很顯然, 此表有待改進!

2. 版本二

觀察生活中的實際情況, 我們發現, 某些網站有普通用戶和VIP用戶, 部分網站的VIP用戶也分了等級. 此時我們思考: 這樣的做法實際上是給用戶分了類, 把我們的用戶分為了不同的角色. 是的, 此時我們再進一步聯想: 我們是否也可以對用戶進行角色划分, 然后再對不同的角色進行權限的分配呢?

  • 分析:
    • 一個人可以有多個角色
    • 一個角色可以有多個人
    • 一個角色可以有多個權限
    • 一個權限可以分配給多個角色

以下是我們的表結構設計:

調整以后的表結構, 由原來的基於用戶的權限控制轉換成基於角色的權限控制(RBAC), 以后再進行權限分配時只需要給指定角色分配一次權限, 給眾多用戶分配指定角色即可.

三. Django項目中進行權限設置

步驟概述:

  • 1.數據庫配置(使用Django自帶數據庫即可)
  • 2.models.py文件: 創建三張表, 分別是用戶表, 角色表, 權限表
  • 3.使用Django自帶的admin來對各個表進行數據添加
  • 4.路由匹配(urls.py文件)
  • 5.視圖函數(views.py文件)
  • 6.自定義中間件

Django生命周期的回顧

在進行Django權限設置之前, 我們首先要回顧一下Django的生命周期:

1. models.py文件配置

  • 創建項目MyLuffyPermission, app名稱為rbac.
  • rbac/models.py: 我們進行權限表結構設計時, 共有5張表, 其中2張是關系表, 所以models.py文件中只有3個model, 分別是權限表, 角色表和用戶表.
  • 數據庫遷移指令
python manage.py makemigrations
python manage.py migrate

2. 使用Django自帶的admin對表進行數據添加

(1) 創建超級用戶

(2) 對rabc/admin.py文件進行配置

from django.contrib import admin
from rbac import models


class PermissionModelAdmin(admin.ModelAdmin):
    list_display = ['title', 'url']  # 展示的字段
    list_editable = ['url']  # 編輯的字段


admin.site.register(models.Permission, PermissionModelAdmin)
admin.site.register(models.Role)
admin.site.register(models.User)

(3)啟動Django項目, 瀏覽器輸入127.0.0.1:8000/admin/, 回車. 對數據庫進行相關信息的添加與修改.

3. rbac組件的開發

在rabc應用中創建一個middlewares的文件夾, 在該文件夾中新建rabc.py, 它就是我們自定義的一個中間件, 作用是權限校驗.

  • rabc/middlewares/rabc.py: 該中間件的編寫分三步走:
    • (1)獲取當前訪問的url
    • (2)獲取當前用戶權限信息
    • (3)權限校驗
  • 具體代碼如下所示:
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
from django.shortcuts import HttpResponse
import re


class RabcMiddleware(MiddlewareMixin):

    def process_request(self, request):
        # 1.獲取當前訪問的URL
        url = request.path_info
        print(111111)
        # 如果當前的url是白名單中的內容,return None,即允許該url通過校驗
        for i in settings.WHITE_LIST:
            if re.match(i, url):  # 如果匹配成功
                return  # 通過校驗

        # 2.獲取當前用戶的權限信息  注意session中的鍵值對是在登錄的時候(web/views/account)設置的
        permission_list = request.session.get(settings.PERMISSION_SESSION_KEY)
        print(222222)
        # 3.權限的校驗
        for i in permission_list:
            # URL權限 匹配成功
            if re.match(r"^{}$".format(i['permissions__url']), url):
                print(333333)
                return
        # 校驗失敗,拒絕訪問
        return HttpResponse('沒有訪問權限')

4. 路由匹配, 視圖函數

(1) MyluffyPermission/urls.py

(2) 創建一個名叫web的app應用, 並在該應用中創建urls.py文件

# 創建app
python manage.py startapp app的名稱

# 注冊app
找到MyluffyPermission/settings.py文件下的INSTALLED_APPS項,然后注冊app

(3) 在web/urls.py文件中寫我們的路由匹配

(4) 在web應用下創建一個名為viewspython包, 對視圖函數進行分類, 每個角色的功能單獨用一個.py文件來寫.

5. 登錄功能

在成功配置完我們的rbac組件之后(主要包括rbac/middlewares/rbac.pyrbac/migrations/middles.py), 我們現在開始進行對登錄功能的編寫.

(1)路由匹配: web/urls.py

from django.conf.urls import url
from web.views import account

urlpatterns = [
	# 用戶登錄
    url(r'^login/$', account.login, name='login'),
]

(2)視圖函數: web/views/account.py

from django.shortcuts import HttpResponse, redirect, render, reverse
from rbac import models
from django.conf import settings


def login(request):
    if request.method == 'POST':
        # 獲取提交的數據
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        # 數據庫匹配管理對象
        obj = models.User.objects.filter(name=user, password=pwd).first()
        if not obj:  # 錯誤優先
            return render(request, 'login.html', {'error_msg': '用戶名或密碼錯誤'})
        # 登錄成功,保存用戶權限信息:
        ret = obj.roles.all().filter(permissions__url__isnull=False).values(
            'permissions__url',
			'permissions__title',).distinct()
        request.session[settings.PERMISSION_SESSION_KEY] = list(ret)
        
        return HttpResponse("登錄成功")
    return render(request, 'login.html')

account.py文件中其中兩行代碼的解釋:

ret = obj.roles.all().filter(permissions__url__isnull=False).values(
   	'permissions__url',
    'permissions__title',).distinct()

"""
obj -- User對象

.roles.all() -- 通過User對象拿到該用戶的所有角色對象(roles)

.filter(permissions__url__isnull=False)
	-- permissions__url ==> 角色對象(roles)跨表查詢Permission表的 URL權限(url)信息
	-- isnull=False ==> isnull表示空,那么isnull=False表示不為空,也就是說 整個ORM語句篩選出了"URL權限不為空的角色對象"
	
.values('permissions__url','permissions__title')
	-- 拿到角色的 URL權限和權限標題 組成的字典
	
.distinct() -- 去重
"""
request.session[settings.PERMISSION_SESSION_KEY] = list(ret)

# request.session[key] = value表示設置session數據
# 由ret=xxx.values(xxx)可知:ret是一個QuerySet對象.
# 由於request.session設置session時,會把數據轉換為json格式,而ret卻是一個QuerySet,因此我們把ret轉換為列表后,就可以設置session了

# PERMISSION_SESSION_KEY是我們自定義的一個配置信息,我們把它寫在settings.py文件里. 配置它的目的是:今后我們再次設置session時,它的key就是一個動態的可變的,如果需要修改key,我們只需要在settings.py文件里重新配置即可,而不再需要找到對應的函數,重復修改.從而達到簡化我們代碼修改的工作量.

(3)模板文件: web/templates/login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="" method="post">
    {% csrf_token %}
    <p>
        用戶名:<input type="text" name="user">
    </p>
    <p>
        密碼:<input type="password" name="pwd">
    </p>
    <p style="color: red">{{ error_msg }}</p>
    <button>登錄</button>
</form>

</body>
</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM