权限管理

权限管理目的:

  1:获取用户的所有权限

  2:动态生成菜单

 

 

一:models的创建  八张表

from  django.db import  models


class User(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    class Meta:
        verbose_name_plural = "用户表"
    def __str__(self):
        return self.username


class Role(models.Model):
    caption = models.CharField(max_length=32)

    class Meta:
        verbose_name_plural = "角色表"
    def __str__(self):
        return self.caption


class User2Role(models.Model):
    u = models.ForeignKey("User",on_delete=models.CASCADE)
    r = models.ForeignKey("Role",on_delete=models.CASCADE)
    class Meta:
        verbose_name_plural = "用户分配角色"
    def __str__(self):
        return "%s-%s"%(self.u.username,self.r.caption)


class Action(models.Model):
    """
    放四条数据,get post ,put,delete 每个url都有基本的增删改查
    """
    caption = models.CharField(max_length=32)
    code  = models.CharField(max_length=32)
    class Meta:
        verbose_name_plural = "操作表"

    def __str__(self):
        return "%s"%(self.caption)



class Permission(models.Model):
    #http://127.0.0.1:8001/user.html/?t=get   获取用户信息
    #http://127.0.0.1:8001/user.html/?t=post  增加用户信息
    #http://127.0.0.1:8001/user.html/?t=delete 删除用户
    #http://127.0.0.1:8001/user.html/?t=put  修改用户
    caption = models.CharField(max_length=32)
    url = models.CharField(max_length=64)
    menu = models.ForeignKey("Menu",on_delete=models.CASCADE,null=True,blank=True)
    class Meta:
        verbose_name_plural = "url表"

    def __str__(self):
        return "%s-%s"%(self.caption,self.url)



class Permission2Action(models.Model):
    p = models.ForeignKey("Permission",on_delete=models.CASCADE)
    a = models.ForeignKey("Action",on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "权限表"

    def __str__(self):
        return "%s-%s:-%s?t=%s" % (self.p.caption,self.a.caption,self.p.url,self.a.code)



class Permission2Action2Role(models.Model):
    p2a = models.ForeignKey("Permission2Action",on_delete=models.CASCADE)
    r = models.ForeignKey("Role",on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "角色分配权限表"

    def __str__(self):
        return "%s==>%s" % (self.r.caption,self.p2a,)


class Menu(models.Model):
    caption = models.CharField(max_length=32)
    parent = models.ForeignKey("self",related_name="p",on_delete=models.CASCADE,null=True,blank=True)

    def __str__(self):
        return self.caption
View Code
用户和角色关系 ---》   User2Role 多对多

url 和 url方法 ---》 Permission2Action 多对多 

角色 和 权限  --- 》 Permission2Action2Role 多对多 

url 和 Menu --> 查看url是否要显示在菜单中

二:组件

class MenuHelper(object):

    def __init__(self,request,username):
        # 当前请求的request对象
        self.request = request
        # 当前用户名
        self.username = username
        # 获取当前URL
        self.current_url = request.path_info

        # 获取当前用户的所有权限
        self.permission2action_dict = None
        # 获取在菜单中显示的权限
        self.menu_leaf_list = None
        # 获取所有菜单
        self.menu_list = None

        self.session_data()

    def session_data(self):
        permission_dict = self.request.session.get('permission_info')
        if permission_dict:
            self.permission2action_dict = permission_dict['permission2action_dict']
            self.menu_leaf_list = permission_dict['menu_leaf_list']
            self.menu_list = permission_dict['menu_list']
        else:
            # 获取当前用户的角色列表
            role_list = models.Role.objects.filter(user2role__u__username=self.username)

            # 获取当前用户的权限列表(URL+Action)
            # v = [
            #     {'url':'/inde.html','code':'GET'},
            #     {'url':'/inde.html','code':'POST'},
            #     {'url':'/order.html','code':'PUT'},
            #     {'url':'/order.html','code':'GET'},
            # ]
            # v = {
            #     '/inde.html':['GET']
            # }
            permission2action_list = models.Permission2Action.objects. \
                filter(permission2action2role__r__in=role_list). \
                values('p__url', 'a__code').distinct()

            permission2action_dict={}
            for item in permission2action_list:
                if item['p__url'] in permission2action_dict:
                    permission2action_dict[item['p__url']].append(item['a__code'])
                else:
                    permission2action_dict[item['p__url']] = [item['a__code'],]

            # 获取菜单的叶子节点,即:菜单的最后一层应该显示的权限
            menu_leaf_list = list(models.Permission2Action.objects. \
                filter(permission2action2role__r__in=role_list).exclude(p__menu__isnull=True). \
                values('p_id', 'p__url', 'p__caption', 'p__menu').distinct())

            # 获取所有的菜单列表
            menu_list = list(models.Menu.objects.values('id', 'caption', 'parent_id'))

            self.request.session['permission_info'] = {
                'permission2action_dict': permission2action_dict,
                'menu_leaf_list': menu_leaf_list,
                'menu_list': menu_list,
            }

            # self.permission2action_list = permission2action_list
            # self.menu_leaf_list = menu_leaf_list
            # self.menu_list = menu_list

    def menu_data_list(self):
        """获取result """

        menu_leaf_dict = {}
        open_leaf_parent_id = None

        # 归并所有的叶子节点
        for item in self.menu_leaf_list:
            item = {
                'id': item['p_id'],
                'url': item['p__url'],
                'caption': item['p__caption'],
                'parent_id': item['p__menu'],
                'child': [],
                'status': True,  # 是否显示
                'open': False  #是否打开菜单
            }
            if item['parent_id'] in menu_leaf_dict:
                menu_leaf_dict[item['parent_id']].append(item)
            else:
                menu_leaf_dict[item['parent_id']] = [item, ]
            if re.match(item['url'], self.current_url):
                item['open'] = True
                open_leaf_parent_id = item['parent_id']

        # 获取所有菜单字典
        menu_dict = {}
        for item in self.menu_list:
            item['child'] = []
            item['status'] = False
            item['open'] = False
            menu_dict[item['id']] = item

        # 讲叶子节点添加到菜单中
        for k, v in menu_leaf_dict.items():
            menu_dict[k]['child'] = v
            parent_id = k
            # 将后代中有叶子节点的菜单标记为【显示】
            while parent_id:
                menu_dict[parent_id]['status'] = True
                parent_id = menu_dict[parent_id]['parent_id'] 

        # 将已经选中的菜单标记为【展开】
        while open_leaf_parent_id:
            menu_dict[open_leaf_parent_id]['open'] = True
            open_leaf_parent_id = menu_dict[open_leaf_parent_id]['parent_id']

        # 生成树形结构数据
        result = []
        for row in menu_dict.values():
            if not row['parent_id']:
                result.append(row)
            else:
                menu_dict[row['parent_id']]['child'].append(row)

        return result

    def menu_content(self,child_list):
        response = ""
        tpl = """
            <div class="item %s">
                <div class="title">%s</div>
                <div class="content">%s</div>
            </div>
        """
        for row in child_list:
            if not row['status']:
                continue
            active = ""
            if row['open']:
                active = "active"
            if 'url' in row:
                response += "<a class='%s' href='%s'>%s</a>" % (active, row['url'], row['caption'])
            else:
                title = row['caption']
                content = self.menu_content(row['child'])
                response += tpl % (active, title, content)
        return response

    def menu_tree(self):
        response = ""
        tpl = """
        <div class="item %s">
            <div class="title">%s</div>
            <div class="content">%s</div>
        </div>
        """
        for row in self.menu_data_list():
            if not row['status']:
                continue
            active = ""
            if row['open']:
                active = "active"
            # 第一层第一个
            title = row['caption']
            # 第一层第一个的后代
            content = self.menu_content(row['child'])
            response += tpl % (active, title, content)
        return response

    def actions(self):
        """
        检查当前用户是否对当前URL有权访问,并获取对当前URL有什么权限
        """
        action_list = []
        # 当前所有权限
        # {
        #     '/index.html': ['GET',POST,]
        # }
        for k,v in self.permission2action_dict.items():
            if re.match(k,self.current_url):
                action_list = v # ['GET',POST,]
                break

        return action_list
View Code

 

实例:

创建装饰器

def permission(func):
    def inner(request,*args,**kwargs):
        user_info = request.session.get('user_info')
        if not user_info:
            return redirect('/login.html')
        obj = MenuHelper(request, user_info['username'])
        action_list = obj.actions()
        if not action_list:
            return HttpResponse('无权限访问')
        kwargs['menu_string'] = obj.menu_tree()
        kwargs['action_list'] = action_list
        return func(request,*args,**kwargs)
    return inner

views:

def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    else:
        username = request.POST.get('username')
        pwd = request.POST.get('pwd')
        obj = models.User.objects.filter(username=username,password=pwd).first()
        if obj:
            # obj.id,  obj.username
            # 当前用户信息放置session中
            request.session['user_info'] = {'nid':obj.id,'username':obj.username}

            # 获取当前用户的所有权限
            # 获取在菜单中显示的权限
            # 获取所有菜单
            # 放置session中
            MenuHelper(request,obj.username)
            return redirect('/index.html')
        else:
            return redirect('/login.html')

def logout(request):
    request.session.clear()
    return redirect('/login.html')

@permission index
= permission(index) def index(request,*args,**kwargs): action_list = kwargs.get('action_list') menu_string = kwargs.get('menu_string') if "GET" in action_list: ##如果有权限为get的时候,我们就可以获取数据,在右侧内容区显示 result = models.User.objects.all() else: result = [] return render(request,'index.html',{'menu_string':menu_string,'action_list':action_list})

 

posted @ 2018-05-08 16:27  你是我的神奇  阅读(250)  评论(0编辑  收藏  举报