Django通用權限設計


新建項目

models:

from django.db import models
from django.contrib.auth.models import User

# Create your models here.


class Customers(models.Model):
    name = models.CharField(max_length=20, verbose_name='姓名')
    phone = models.CharField(max_length=15, verbose_name='電話')
    owner = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name='所屬用戶')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '客戶表'
        verbose_name_plural = verbose_name

        permissions = (
            ('show_all_customer', '查看所有客戶'),
            ('show_own_customer', '查看自己的客戶')
        )

‘show_all_customer’:這個是需要留意一下的,后面要用到. django的權限匹配 request.user.has_prem(“app.show_all_customer”) 就是將 app名 和 這個名稱用.連接之后匹配的。

‘查看所有客戶’ 這個就是顯示在后台權限列表里的描述。

image

這里只列舉兩個權限簡單說明一下用法,一個是查看所有客戶,一個是查看自己的客戶。

views:

from django.shortcuts import render

from app.models import Customers
from app.perm_check import check_permission

# Create your views here.


def show_all(request):
    customer_list = Customers.objects.all()
    return render(request, 'app/list.html', locals())


def show_own(request):
    uid = request.GET.get('uid', None)
    if uid:
        customer_list = Customers.objects.filter(owner_id=uid)

    return render(request, 'app/list.html', locals())

urls:

假設:訪問所有客戶列表 http://localhost:8000/all

訪問自己的客戶列表需要加參數uid ,  http://localhost:8000/own/?uid=2

from django.contrib import admin
from django.urls import path
from app.views import show_all, show_own

urlpatterns = [
    path('admin/', admin.site.urls),
    path('all/', show_all, name='show_all'),
    path('own/', show_own, name='show_own'),
]

settings.py中添加應用“app”, 我取的名字叫app.  並設置模版目錄 “templates”.

同步數據庫,並創建超級管理員

python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser

啟動項目,進入后台,添加數據

image

用戶 zhangsan, lisi給予登錄后台的權限,登錄了后台,就等於用戶已經登錄了,訪問其它非后台頁面也是登錄狀態。


權限設計

app目錄下新建 prem_list.py文件

perm_list = {
    'app_show_all_customer': ['show_all', 'GET', []],
    'app_show_own_customer': ['show_own', 'GET', ['uid',]]
}

大體思路是這樣: 請求過來之后,先到prem_list中去匹配 ‘show_all’這樣的url_name, 然后再匹配 請求方法,再去列表中 匹配參數,如果都匹配上了,說明有給設置權限。那么再用request.user.has_perm()方法確定權限是否跟當前用戶綁定了,如果綁定了說明有權限。

寫一個權限檢測的方法,和一個裝飾器

app/perm_check.py

from django.urls import resolve
from django.shortcuts import render

from app.perm_list import perm_list


def check(request, *args, **kwargs):
    url_obj = resolve(request.path_info)
    url_name = url_obj.url_name
    print('>>>>:', '權限匹配')

    if request.user.is_superuser:
        return True

    if url_name:
        url_method = request.method

        for k, v in perm_list.items():
            per_url_name = v[0]
            per_method = v[1]
            per_args = v[2]

            args_match = False
            #匹配perm_list中的權限
            if per_url_name == url_name and url_method == per_method:
                method_func = getattr(request, url_method)

                for arg in per_args:
                    if method_func.get(arg):
                        args_match = True
                    else:
                        args_match = False
                        break
                else:
                    args_match = True

            #prem_list權限匹配上了
            if args_match:
                app_name, perm_name = k.split('_', 1)
                perm_str = '%s.%s' % (app_name, perm_name)
                print('>>>>: ', perm_name)
                if request.user.has_perm(perm_str):
                    return True
                else:
                    return False
        else:
            return False


    else:
        return False   #沒有匹配上權限,默認不允許



#裝飾器
def check_permission(fun):
    def inner(request, *args, **kwargs):
        if check(request, *args, **kwargs):
            return fun(request, *args, **kwargs)
        return render(request, 'app/403.html', locals())
    return inner


權限到這就寫完了。

模版

image

list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table>
        <tr>
            <th>姓名</th>
            <th>電話</th>
            <th>所屬用戶</th>
        </tr>
        {% for c in customer_list %}
        <tr>
            <td>{{ c.name }}</td>
            <td>{{ c.phone }}</td>
            <td>{{ c.owner }}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

403.html

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

現在給兩個視圖加上裝飾器,檢測 權限

from django.shortcuts import render

from app.models import Customers
from app.perm_check import check_permission

# Create your views here.

@check_permission
def show_all(request):
    customer_list = Customers.objects.all()
    return render(request, 'app/list.html', locals())

@check_permission
def show_own(request):
    uid = request.GET.get('uid', None)
    if uid:
        customer_list = Customers.objects.filter(owner_id=uid)

    return render(request, 'app/list.html', locals())


給zhangsan分配查看所有客戶的權限 ,lisi分配 查看自己客戶 的權限 ,測試 一下

使用zhangsan登錄后台后 :

查看所有客戶

image

查看自己的客戶:

image

image

再使用lisi登錄后台:

image

image

image

這里發現一個問題,手動改變uid的值 后,lisi也能看到zhangsan的客戶,這就不符合要求了。

要解決這個問題,可以使用勾子函數的方法 。

定義勾子函數

app/perm_hook.py

def own_hook(request):
    uid = request.GET.get('uid', None)
    if uid == str(request.user.id):
        return True
    return False

修改 app/perm_list.py

from app import perm_hook

perm_list = {
    'app_show_all_customer': ['show_all', 'GET', []],
    'app_show_own_customer': ['show_own', 'GET', ['uid',], perm_hook.own_hook]
}

修改 app/perm_check.py

from django.urls import resolve
from django.shortcuts import render

from app.perm_list import perm_list


def check(request, *args, **kwargs):
    url_obj = resolve(request.path_info)
    url_name = url_obj.url_name
    print('>>>>:', '權限匹配')

    if request.user.is_superuser:
        return True

    if url_name:
        url_method = request.method

        for k, v in perm_list.items():
            per_url_name = v[0]
            per_method = v[1]
            per_args = v[2]

            args_match = False
            #匹配perm_list中的權限
            if per_url_name == url_name and url_method == per_method:
                method_func = getattr(request, url_method)

                for arg in per_args:
                    if method_func.get(arg):
                        args_match = True
                    else:
                        args_match = False
                        break
                else:
                    args_match = True

            hook_match = True
            if len(v) >= 4:
                hook_func = v[3]
                hook_match = hook_func(request)

            #prem_list權限匹配上了
            if args_match and hook_match:
                app_name, perm_name = k.split('_', 1)
                perm_str = '%s.%s' % (app_name, perm_name)
                print('>>>>: ', perm_name)
                if request.user.has_perm(perm_str):
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False


    else:
        return False   #沒有匹配上權限,默認不允許



#裝飾器
def check_permission(fun):
    def inner(request, *args, **kwargs):
        if check(request, *args, **kwargs):
            return fun(request, *args, **kwargs)
        return render(request, 'app/403.html', locals())
    return inner

修改完之后,啟動應用 ,再用lisi訪問zhangsan的客戶:

image

發現已經 不能訪問了,再訪問一下自己的客戶:

image


免責聲明!

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



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