• Django——权限组件(中间件判断用户权限--URL初级)


    权限

    根据URL进行限制用户可以访问的资源

    项目与应用的关系

    项目可包含多个应用
    应用可包含在多个项目中
    RBAC:基于权限的管理系统

    项目

    先创建一个Django项目

    Model

    from django.db import models
    
    
    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32,default=123)
        email = models.EmailField()
        roles = models.ManyToManyField(to="Role")
    
        def __str__(self):
            return self.name
    
    
    class Role(models.Model):
        title =models.CharField(max_length=32)
        permissions = models.ManyToManyField(to="Permission")
    
        def __str__(self):
            return self.title
    
    
    class Permission(models.Model):
        url = models.CharField(max_length=32)
        title = models.CharField(max_length=32)
    
        def __str__(self):
            return self.title

    前端模板

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <p>用户名<input type="text" name="user"></p>
        <p>密码<input type="password" name="pwd"></p>
        <p><input type="submit"  value="登录"></p>
    
    </form>
    </body>
    </html>

    URL

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/', views.login),
        url(r'^users/', views.user_list),
        url(r'^orders/', views.role_list),
    ]

    后端

    from django.shortcuts import render, HttpResponse, redirect
    from rbac.models import UserInfo, Role, Permission
    
    
    def login(request):
        if request.method == "GET":
            return render(request, "login.html")
        if request.method == "POST":
            username = request.POST.get("user")
            pwd = request.POST.get("pwd")
            user = UserInfo.objects.filter(name=username, pwd=pwd).first()
            if user:
                request.session["user_id"] = user.pk
                permission_list = user.roles.all().values("permissions__url", "permissions__title").distinct()
                temp = []
                for per_url in permission_list:
                    temp.append(per_url["permissions__url"])
                request.session["permissions_list"] = temp
                print(temp)
                return HttpResponse("OK")
            else:
                return redirect('/login/')
    
    
    def user_list(request):
        return HttpResponse("用户列表")
    
    
    def role_list(request):
        return HttpResponse("订单列表")

    后端有很多的视图函数,如果编写装饰器进行判断用户是否有权限访问,有三十个视图函数,就需要在三十个视图函数上添加装饰器函数,因此装饰器的方法不太妥当,取而代之的是中间件的方法

    from django.utils.deprecation import MiddlewareMixin  #注意
    from django.shortcuts import render,redirect, HttpResponse
    from rbac.models import UserInfo
    import re  #注意
    
    class M1(MiddlewareMixin):
        def process_request(self,request):
            current_path = request.path_info
            permission_list = request.session.get("permissions_list")
            print(permission_list)
            valid_menu = ["/login/","/reg/","/admin/.*"]  # 如果不设置白名单,admin的url也会被判为无权限,而且不需要验证的函数少, 先设置白名单,
                                            # 如果用户输入的url在白名单中就会return None
            for valid_url  in valid_menu:
                ret = re.match(valid_url,current_path)   #注意
                if ret:
                    return None
            if not permission_list:
                return None
            Flage = False
            for per_url in permission_list:
                re_macth = re.match(per_url,current_path)
                if re_macth:
                    Flage = True
                    break
            if not Flage:
                return HttpResponse("无权限")

    再次解耦后端

    在rabc应用之service包intiale 模块中创建一个inital_session函数,登录后处理session

    from rbac.service.initial import inital_session
    
    def login(request):
        if request.method == "GET":
            return render(request, "login.html")
        if request.method == "POST":
            username = request.POST.get("user")
            pwd = request.POST.get("pwd")
            user = UserInfo.objects.filter(name=username, pwd=pwd).first()
            if user:
                inital_session(request,user)
                return HttpResponse("OK")
            else:
                return redirect('/login/')
    url_filter  模块下的代码
    def inital_session(request,user):
        request.session["user_id"] = user.pk
        permission_list = user.roles.all().values("permissions__url", "permissions__title").distinct()
        temp = []
        for per_url in permission_list:
            temp.append(per_url["permissions__url"])
        request.session["permissions_list"] = temp

    目录结构如下图

    创建中间价的步骤

      1、在项目中创建一个应用application,自己命名至于为什么?这是前面提到的:“一个应用可以包含在多个项目中”,方便以后的使用

      2、在项目中创建一个文件夹service,

      3、在service 中创建一个py文件,存放自己中间件类

      4、创建一个类,必须继承  MiddlewareMixin

      5、该类中必须有一个函数,process_request

      6、在该文件下面创建一个inital_session 的模块,处理登录后,session

    做好以上步骤,效果如下图

     上面的介绍如何使用中间件控制用户的访问那个函数,下面介绍,根据用户的角色展示菜单

    二级菜单

    用户登录成功,在cookie中写入用户的权限

    import re
    
    
    def inital_session(request, user):
        request.session["user_id"] = user.pk
        permission_info = user.roles.all().values(
            "permissions__url",  # 权限url
            "permissions__code",  #
            "permissions__title",
            "permissions__id",
            "permissions__permission_group_id",
            "permissions__parent",
            "permissions__parent_id",
            "permissions__permission_group__menu__caption",
            "permissions__permission_group__menu__id",
    
        ).distinct()
        print(permission_info)
        # 设置用户权限
        dic = {}
        for per_info in permission_info:
            gid = per_info["permissions__permission_group_id"]
            if gid not in dic:
                dic[gid] = {
                    "urls": [per_info["permissions__url"]],
                    "codes": [per_info["permissions__code"]]
                }
            else:
                dic[gid]["urls"].append(per_info["permissions__url"])
                dic[gid]["codes"].append(per_info["permissions__code"])
        request.session["permissions_dict"] = dic
    
        ## 设置用户的菜单
        permission_list = []
        for permission_item in permission_info:
           temp = {
               "id":permission_item["permissions__id"],
               "title":permission_item["permissions__title"],
               "url":permission_item["permissions__url"],
               "pid":permission_item["permissions__parent_id"],
               "menu_name":permission_item["permissions__permission_group__menu__caption"],
               "menu_id":permission_item['permissions__permission_group__menu__id'],
           }
           permission_list.append(temp)
    
        request.session["permission_list"] = permission_list
    View Code

    由于菜单是通用,每个函数都是需要处理菜单的逻辑,所有单独拿出来进行创建一个处理菜单的模块,使用@register.inclusion_tag 标签。

    自定义register.inclusion_tag标签

    from django import template
    
    register=template.Library()
    
    @register.inclusion_tag("menu.html")
    def get_menu(request):
        permission_list = request.session["permission_list"]
    
        #############temp_dict:存储所有放到菜单栏中的权限
        temp_dict = {}
        print(permission_list)
        for item in permission_list:
            pid = item["pid"]
            if not pid:
                item["active"] = False
                temp_dict[item["id"]] = item
    
    
    
    
        #######将需要标中的active设置True
        # print(permission_list)
        current_path = request.path_info
        import re
        for item in permission_list:
            pid = item["pid"]
            url = "^%s$" % item["url"]
            if re.match(url, current_path):
                if pid:
                    temp_dict[pid]["active"] = True
                else:
                    item["active"] = True
    
        ########将temp_dict转换为最终的menu_dict的数据格式
    
        menu_dict = {}
        for item in temp_dict.values():
    
            if item["menu_id"] in menu_dict:
    
                temp = {"title": item["title"], "url": item["url"], "active": item["active"]},
                menu_dict[item["menu_id"]]["children"].append(temp)
    
                if item["active"]:
                    menu_dict[item["menu_id"]]["active"] = True
            else:
    
                menu_dict[item["menu_id"]] = {
    
                    "title": item["menu_name"],
                    "active": item["active"],
                    "children": [
                        {"title": item["title"], "url": item["url"], "active": item["active"]},
                    ]
    
                }
        print(menu_dict)
    
        return {"menu_dict":menu_dict}
    inclusion_tag标签
    def m1(request):
        # # menu_dict = {
        # #     1: {
        # #         "title": "菜单一",
        # #         "active": False,
        # #         "children": [
        # #             {"title": "添加用户", "url": "xxxxxxxxxxx", "active": False},
        # #             {"title": "查看用户", "url": "xxxxxxxxxxx", "active": False},
        # #
        # #         ]},
        # #
        # #     2: {
        # #         "title": "菜单二",
        # #         "active": True,
        # #         "children": [
        # #             {"title": "添加用户", "url": "xxxxxxxxxxx", "active": True},
        # #             {"title": "查看用户", "url": "xxxxxxxxxxx", "active": True},
        # #
        # #         ]
        # #
        # #     }}
        #
        premission_list = request.session["permission_list"]
        print(premission_list)
        #存储放到菜单栏中的权限
        temp_dict = {}
        for item in premission_list:
            if not item["pid"]:
                item["active"] = False  #添加到菜单栏时,添加一个是否展开的标志
                temp_dict[item["id"]]= item
    
        #将需要标中的active设置为True
        current_path = request.path_info
        import re
        for item in premission_list:
            pid = item["pid"]
            url = "%s$"%item["url"]
            if re.match(url,current_path):
                if pid:                     #判断是不是二级菜单,如果是,就会把该菜单上一级设置为Ture
                    temp_dict[pid]["active"]=True
                else:
                    item["avtive"] = True   #注意此时的item 和temp_dict 的数据同一条数据,这里修改了True,temp_dict 也会改为True
        print(temp_dict)
        #将数据最终构造成最终的menu_dict数据
    
        menu_dict = {}
        for item in temp_dict.values():
            if item["menu_id"] in menu_dict:
                temp = {"title":item["title","url":item["url"],"active":item["avtive"]]} #定义一个自己的字典结构体
                menu_dict[item["menu_id"]]["children"].append(temp) #把菜单添加到一级菜单中
                if item["active"] == True:   #如果二级菜单是展开的,那么一级菜单也是展开的
                    menu_dict[item["menu_id"]]["active"] = True
            else:
                menu_dict[item["menu_id"]] = {
                    "title":item["menu_name"],
                    "active":False,
                    "children":[
                        {"title":item["title"],"url":item["url"],"active":item["active"],}
                    ]
                }
        print(menu_dict)
    
    
    
    
    
        return render(request, "m1.html")
    注释*函数版本

    前端页面

    {% load my_tags %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <style>
            .header {
                 100%;
                height: 50px;
                background-color: #336699;
            }
    
            .menu, .content {
                float: left;
            }
    
            .menu {
                 200px;
                height: 600px;
                background-color: darkgray;
            }
    
            .hide {
                display: none;
            }
    
            .menu .title {
                font-size: 16px;
                color: #336699 !important;
                margin: 20px 0;
            }
    
            .con a {
                margin-left: 30px;
                color: white;
            }
    
            .active {
                color: red !important;
            }
        </style>
    </head>
    <body>
    
    <div class="header"></div>
    
    <div class="box">
        {% mul 1 2 %}
       {% get_menu request %}
    
    
    
        <div class="content">
            {% block con %}
    
            {% endblock %}
        </div>
    
    </div>
    
    
    </body>
    </html>
    View Code
  • 相关阅读:
    MSMQ实现自定义序列化存储
    流程部署的查询、删除、流程
    使用trello管理你的项目
    CentOS 6.4 编译安装 gcc 4.8.1
    jquery实现无限滚动瀑布流实现原理
    系统分析员备考之经济管理篇(二)
    架构、架构师和架构设计
    ASP.net Web API综合示例
    c中函数参数传递
    准备抽象NHibernate和EntityFramework
  • 原文地址:https://www.cnblogs.com/huyangblog/p/8508977.html
Copyright © 2020-2023  润新知