首页 > 其他 > 详细

Django通用权限设计

时间:2020-04-16 15:58:56      阅读:58      评论:0      收藏:0      [点我收藏+]

新建项目

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名 和 这个名称用.连接之后匹配的。

‘查看所有客户’ 这个就是显示在后台权限列表里的描述。

技术分享图片

这里只列举两个权限简单说明一下用法,一个是查看所有客户,一个是查看自己的客户。

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

启动项目,进入后台,添加数据

技术分享图片

用户 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


权限到这就写完了。

模版

技术分享图片

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登录后台后 :

查看所有客户

技术分享图片

查看自己的客户:

技术分享图片

技术分享图片

再使用lisi登录后台:

技术分享图片

技术分享图片

技术分享图片

这里发现一个问题,手动改变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的客户:

技术分享图片

发现已经 不能访问了,再访问一下自己的客户:

技术分享图片

Django通用权限设计

原文:https://www.cnblogs.com/huangxm/p/12712858.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!