• 271 第九篇:BBS项目02:基于角色权限管理:rbac具体代码实现


    1、settings

      1 """
      2 Django settings for day80 project.
      3 
      4 Generated by 'django-admin startproject' using Django 1.11.6.
      5 
      6 For more information on this file, see
      7 https://docs.djangoproject.com/en/1.11/topics/settings/
      8 
      9 For the full list of settings and their values, see
     10 https://docs.djangoproject.com/en/1.11/ref/settings/
     11 """
     12 
     13 import os
     14 
     15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
     16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
     17 
     18 
     19 # Quick-start development settings - unsuitable for production
     20 # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
     21 
     22 # SECURITY WARNING: keep the secret key used in production secret!
     23 SECRET_KEY = '7x(f$0j0c#)hn)8i(uv6j*sg^h_7v9$eak#pu_n4ji05=v28ca'
     24 
     25 # SECURITY WARNING: don't run with debug turned on in production!
     26 DEBUG = True
     27 
     28 ALLOWED_HOSTS = []
     29 
     30 
     31 # Application definition
     32 
     33 INSTALLED_APPS = [
     34     'django.contrib.admin',
     35     'django.contrib.auth',
     36     'django.contrib.contenttypes',
     37     'django.contrib.sessions',
     38     'django.contrib.messages',
     39     'django.contrib.staticfiles',
     40     'app01.apps.App01Config',
     41     'rbac',
     42 ]
     43 from django.middleware.common import CommonMiddleware
     44 MIDDLEWARE = [
     45     'django.middleware.security.SecurityMiddleware',
     46     'django.contrib.sessions.middleware.SessionMiddleware',
     47     'django.middleware.common.CommonMiddleware',
     48     'django.middleware.csrf.CsrfViewMiddleware',
     49     'django.contrib.auth.middleware.AuthenticationMiddleware',
     50     'django.contrib.messages.middleware.MessageMiddleware',
     51     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     52     'rbac.middlewear.rbac.Middle',
     53 ]
     54 
     55 ROOT_URLCONF = 'day80.urls'
     56 
     57 TEMPLATES = [
     58     {
     59         'BACKEND': 'django.template.backends.django.DjangoTemplates',
     60         'DIRS': [os.path.join(BASE_DIR, 'templates')]
     61         ,
     62         'APP_DIRS': True,
     63         'OPTIONS': {
     64             'context_processors': [
     65                 'django.template.context_processors.debug',
     66                 'django.template.context_processors.request',
     67                 'django.contrib.auth.context_processors.auth',
     68                 'django.contrib.messages.context_processors.messages',
     69             ],
     70         },
     71     },
     72 ]
     73 
     74 WSGI_APPLICATION = 'day80.wsgi.application'
     75 
     76 
     77 # Database
     78 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
     79 
     80 DATABASES = {
     81     'default': {
     82         'ENGINE': 'django.db.backends.sqlite3',
     83         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
     84     }
     85 }
     86 
     87 
     88 # Password validation
     89 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
     90 
     91 AUTH_PASSWORD_VALIDATORS = [
     92     {
     93         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
     94     },
     95     {
     96         'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
     97     },
     98     {
     99         'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    100     },
    101     {
    102         'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    103     },
    104 ]
    105 
    106 
    107 # Internationalization
    108 # https://docs.djangoproject.com/en/1.11/topics/i18n/
    109 
    110 LANGUAGE_CODE = 'en-us'
    111 
    112 TIME_ZONE = 'UTC'
    113 
    114 USE_I18N = True
    115 
    116 USE_L10N = True
    117 
    118 USE_TZ = True
    119 
    120 
    121 # Static files (CSS, JavaScript, Images)
    122 # https://docs.djangoproject.com/en/1.11/howto/static-files/
    123 
    124 STATIC_URL = '/static/'
    125 # ==========静态文件配置=========
    126 STATICFILES_DIRS = (
    127     os.path.join(BASE_DIR,'static'),
    128 )
    129 # ==========rbac============
    130 PERMISSION_URL_DICT = "permission_url_list"
    131 PERMISSION_MENU_KEY = "permission_menu_list"
    132 
    133 # =========白名单(不需要权限就可以看到的)==========
    134 WHITE_LIST =[
    135      "/login/",
    136      "/admin.*",
    137      "/index/",
    138 ]
    settings.py

    2、rbac应用下的models

     1 from django.db import models
     2 
     3 # Create your models here.
     4 class Role(models.Model):
     5     title = models.CharField(max_length=32,verbose_name="角色")
     6     permissions = models.ManyToManyField(to="Permission",verbose_name="拥有权限的角色",blank=True)  #权限和角色是多对多的关系
     7 
     8     def __str__(self):
     9         return self.title
    10     class Meta:
    11         verbose_name_plural = "角色表"
    12 
    13 class Permission(models.Model):
    14     title = models.CharField(max_length=32,verbose_name="权限名")
    15     url = models.CharField(max_length=32,verbose_name="带正则的url")
    16     codes = models.CharField(max_length=32,verbose_name="代码")
    17     group = models.ForeignKey(to="Group",verbose_name="所属组",blank=True)  #组和权限是一对多的关系,一个组有多个权限
    18     menu_gp = models.ForeignKey(to='Permission',related_name='aaa',null=True,blank=True,verbose_name="组内菜单")
    19     def __str__(self):
    20         return self.title
    21     class Meta:
    22         verbose_name_plural = "权限表"
    23 
    24 class UserInfo(models.Model):
    25     name = models.CharField(max_length=32,verbose_name="姓名")
    26     password = models.CharField(max_length=64,verbose_name="密码")
    27     email = models.CharField(max_length=32,verbose_name="邮箱")
    28     roles = models.ManyToManyField(to="Role",blank=True)  #用户和角色是多对多的关系
    29     def __str__(self):
    30         return self.name
    31     class Meta:
    32         verbose_name_plural = "用户表"
    33 
    34 class Group(models.Model):
    35     title = models.CharField(max_length=32,verbose_name="组名称")
    36     menu = models.ForeignKey(to="Menu",verbose_name="组内菜单",blank=True)  #一个组下有多个菜单
    37     def __str__(self):
    38         return self.title
    39     class Meta:
    40         verbose_name_plural = ""
    41 
    42 class Menu(models.Model):
    43     caption = models.CharField(max_length=32,verbose_name="菜单")
    44     def __str__(self):
    45         return self.caption
    46     class Meta:
    47         verbose_name_plural = "菜单表"
    models.py

    3、urls

     1 from django.conf.urls import url
     2 from django.contrib import admin
     3 from app01 import views
     4 urlpatterns = [
     5     url(r'^admin/', admin.site.urls),
     6     url(r'^login/$', views.login),
     7     url(r'^index/$', views.index),
     8     url(r'^userinfo/$', views.userinfo),
     9     url(r'^userinfo/add/$', views.userinfo_add),
    10     url(r'^userinfo/del/(d+)/$', views.userinfo_del),
    11     url(r'^userinfo/edit/(d+)/$', views.userinfo_edit),
    12     url(r'^order/$', views.order),
    13     url(r'^order/add/$', views.order_add),
    14     url(r'^order/del/(d+)/$', views.order_del),
    15     url(r'^order/edit/(d+)/$', views.order_edit),
    16 ]
    urls.py

    4、初始化   server--init_permission

     1 #!usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 from django.conf import settings
     4 def init_permission(user, request):
     5     '''
     6     初始化权限信息,获取权限信息并放置到session中
     7     :param user:
     8     :param request:
     9     :return:
    10     '''
    11     permission_list = user.roles.values('permissions__id',
    12                                         'permissions__title',  # 用户列表
    13                                         'permissions__url',
    14                                         'permissions__codes',
    15                                         'permissions__menu_gp_id',  # 组内菜单ID,Null表示是菜单
    16                                         'permissions__group_id',
    17                                         'permissions__group__menu_id',  # 菜单ID
    18                                         'permissions__group__menu__caption',  # 菜单名称
    19                                         ).distinct()  # 获取当前角色对象的所有的权限并去重
    20     # print(permission_list)
    21     # 权限相关
    22     url_dict = {}
    23     for item in permission_list:
    24         group_id = item["permissions__group_id"]
    25         url = item["permissions__url"]
    26         code = item["permissions__codes"]
    27         # print("code_list", code)
    28         if group_id in url_dict:
    29             url_dict[group_id]["code"].append(code)  # 如果id在里面就把code和url添加进去
    30             url_dict[group_id]["urls"].append(url)
    31         else:
    32             # 如果不在就设置
    33             url_dict[group_id] = {
    34                 "code": [code, ],
    35                 "urls": [url, ]
    36             }
    37     request.session[settings.PERMISSION_URL_DICT] = url_dict
    38     print(url_dict)
    39 
    40 
    41     #菜单相关
    42     # 1、先去掉不是菜单的
    43     menu_list = []
    44     for item in permission_list:
    45         tpl = {
    46             "id":item["permissions__id"],
    47             "title":item["permissions__title"],
    48             "url":item["permissions__url"],
    49             "menu_gp_id":item["permissions__menu_gp_id"],
    50             "menu_id":item["permissions__group__menu_id"],
    51             "menu_title":item["permissions__group__menu__caption"]
    52         }
    53         menu_list.append(tpl)
    54     request.session[settings.PERMISSION_MENU_KEY] = menu_list
    55     print("============",menu_list)
    sever下的init_permission.py

    5、app01下的views

    views.py
     1 from django.shortcuts import render, redirect, HttpResponse
     2 from django.conf import settings
     3 # Create your views here.
     4 from rbac import models
     5 import re
     6 from rbac.service.init_permission import init_permission
     7 class BasePagPermission(object):
     8     def __init__(self, code_list):
     9         self.code_list = code_list
    10 
    11     def has_add(self):
    12         if "add" in self.code_list:
    13             return True
    14 
    15     def has_del(self):
    16         if "del" in self.code_list:
    17             return True
    18 
    19     def has_edit(self):
    20         if "edit" in self.code_list:
    21             return True
    22 
    23 
    24 def login(request):
    25     if request.method == "GET":
    26         return render(request, "login.html")
    27     else:
    28         username = request.POST.get("username")
    29         password = request.POST.get("password")
    30         user = models.UserInfo.objects.filter(name=username, password=password).first()
    31         if user:
    32             init_permission(user, request)
    33             return redirect("/userinfo/")
    34         else:
    35             return render(request, "login.html")
    36 
    37 
    38 def index(request):
    39     return render(request, "index.html")
    40 
    41 
    42 def userinfo(request):
    43     pagpermission = BasePagPermission(request.permission_code_url)  # 实例化
    44     # print("code......", request.permission_code_url)
    45     data_list = [
    46         {"id": 1, "name": "haiyan1"},
    47         {"id": 2, "name": "haiyan2"},
    48         {"id": 3, "name": "haiyan3"},
    49         {"id": 4, "name": "haiyan4"},
    50         {"id": 5, "name": "haiyan5"},
    51     ]
    52     #print("data_list",data_list)
    53     #print("pagpermission",pagpermission)
    54     return render(request, "userinfo.html", {"data_list": data_list, "pagpermission": pagpermission})
    55 
    56 
    57 def userinfo_add(request):
    58     if request.method == "GET":
    59         return render(request,"userinfo_add.html")
    60     else:
    61         return redirect("/userinfo/")
    62 
    63 
    64 def userinfo_del(request, nid):
    65     return HttpResponse("删除用户")
    66 
    67 
    68 def userinfo_edit(request, nid):
    69     return HttpResponse("编辑用户")
    70 
    71 
    72 def order(request):
    73     pagpermission = BasePagPermission(request.permission_code_url)  # 实例化
    74     print("code......", request.permission_code_url)
    75     return render(request,"order.html",{"pagpermission":pagpermission})
    76 
    77 
    78 def order_add(request):
    79     return HttpResponse("添加订单")
    80 
    81 
    82 def order_del(request, nid):
    83     return HttpResponse("删除订单")
    84 
    85 
    86 def order_edit(request, nid):
    87     return HttpResponse("编辑订单")
    views.py

    6、中间件

     1 #!usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 from django.shortcuts import render, redirect, HttpResponse
     4 from django.conf import settings
     5 import re
     6 
     7 
     8 class MiddlewareMixin(object):
     9     def __init__(self, get_response=None):
    10         self.get_response = get_response
    11         super(MiddlewareMixin, self).__init__()
    12 
    13     def __call__(self, request):
    14         response = None
    15         if hasattr(self, 'process_request'):
    16             response = self.process_request(request)
    17         if not response:
    18             response = self.get_response(request)
    19         if hasattr(self, 'process_response'):
    20             response = self.process_response(request, response)
    21         return response
    22 
    23 
    24 class Middle(MiddlewareMixin):  # 必须去继承这个类
    25     def process_request(self, request):
    26         current_url = request.path_info  # 获取当前请求的路径
    27 
    28         # 如果匹配的是白名单里面的就让通过,不需要权限
    29         for url in settings.WHITE_LIST:
    30             if re.match(url, current_url):
    31                 return None
    32         permission_dict = request.session.get(settings.PERMISSION_URL_DICT)  # 获取session
    33         if not permission_dict:  # 如果没有得到,就直接跳转到login页面
    34             return redirect("/login/")
    35 
    36         flag = False
    37         for group_id, code_url in permission_dict.items():
    38             for db_url in code_url["urls"]:
    39                 regex = "^{0}$".format(db_url)
    40                 # 因为match匹配的时候会把你只要有的都匹配到了,我们只匹配当前的url,所以得加一个起始终止符
    41                 # print(regex, current_url)
    42                 if re.match(regex, current_url):
    43                     # print(1111111)
    44                     request.permission_code_url = code_url["code"]  # 用户输入的url和数据库的url匹配成功之后成功之后先把code保存在request中,方便以后判断
    45                     flag = True
    46                     break  # 如果匹配成功就进入页面
    47                     # 注意在这里不能用return,在中间件中process_request这个函数如果有return就只会执行自己的
    48                     #   response和上面的response,不会执行后续的。没有return就会去继续执行后续中间件和视图函数
    49             if flag:  # 结束外层循环
    50                 break
    51         if not flag:
    52             return HttpResponse("无权访问")  # 如果访问不成功就显示无权访问
    53 
    54     def process_reponse(self, request, response):
    55         return response
    middlewear下的rbac.py

    7、templatetags下的rbac.py

     1 #!usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 from django.conf import settings
     4 import re
     5 from django.template import Library
     6 register = Library()
     7 @register.inclusion_tag("xxxx.html")
     8 def menu_html(request):
     9     """
    10        去Session中获取菜单相关信息,匹配当前URL,生成菜单
    11        :param request:
    12        :return:
    13        """
    14     menu_list = request.session.get(settings.PERMISSION_MENU_KEY)
    15     current_url = request.path_info
    16     menu_dict = {}
    17     for item in menu_list:
    18         # 循环找到可以作为菜单的权限
    19         if not item["menu_gp_id"]:
    20             menu_dict[item["id"]] = item
    21     # 正则匹配添加active
    22     for item in menu_list:
    23         regex = "^{0}$".format(item["url"])
    24         if re.match(regex, current_url):
    25             # 匹配成功在根据id去判断,如果菜单id有值就不是菜单,则去找它的值对应的id,添加active
    26             # ,为null时就是菜单,直接给自己添加一个active
    27             if not item["menu_gp_id"]:  #是菜单
    28                 menu_dict[item["id"]]["active"] = True
    29             else:
    30                 menu_dict[item["menu_gp_id"]]["active"] = True
    31 
    32     result = {}
    33     for item in menu_dict.values():
    34         active = item.get("active")
    35         menu_id = item["menu_id"]
    36         if menu_id in result:
    37             result[menu_id]["children"].append({'title': item['title'], 'url': item['url'], 'active': active})
    38             if active:
    39                 result[menu_id]["active"] = True
    40         else:
    41             result[menu_id] = {
    42                 'menu_id': item['menu_id'],
    43                 'menu_title': item['menu_title'],
    44                 'active': active,
    45                 'children': [
    46                     {'title': item['title'], 'url': item['url'], 'active': active}
    47                 ]
    48             }
    49     print("result",result)
    50     return {"menu_dict":result}
    自定义标签rbac.py

    8、template

     1 {% load rbac %}
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     7     <meta name="viewport" content="width=device-width">
     8     <title>Title</title>
     9     <link rel="stylesheet" href="/static/rbac/rbac.css">
    10 </head>
    11 <body>
    12 <div class="aaa">
    13     <div class="left">
    14         {% menu_html request %}
    15     </div>
    16     <div class="right">
    17         {% block content %}
    18 
    19         {% endblock %}
    20     </div>
    21 </div>
    22 <script src="/static/jquery-3.2.1.min.js"></script>
    23 <script src="/static/rbac/rbac.js"></script>
    24 
    25 </body>
    26 </html>
    base.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width">
     7     <title>Title</title>
     8 </head>
     9 <body>
    10 <h1>hello--{{ user.name }}</h1>
    11 </body>
    12 </html>
    index.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width">
     7     <title>Title</title>
     8 </head>
     9 <body>
    10 <form method="post" action="/login/">
    11     {% csrf_token %}
    12     <p>姓名:<input type="text" name="username"></p>
    13     <p>密码:<input type="password" name="password"></p>
    14     <p><input type="submit" value="提交"></p>
    15 </form>
    16 </body>
    17 </html>
    login.html
    1 {% extends "base.html" %}
    2 {% block content %}
    3 <h1>订单页面</h1>
    4 {% endblock %}
    order.html
     1 {% extends "base.html" %}
     2 {% block content %}
     3 {% if pagpermission.has_add %}
     4         <a href="/userinfo/add/">添加</a>
     5         {% endif %}
     6         <table border="1">
     7             <thead>
     8                 <th>编号</th>
     9                 <th>姓名</th>
    10                 <th>操作</th>
    11             </thead>
    12             <tbody>
    13             {% for row in data_list %}
    14                 <tr>
    15                     <td>{{ row.id }}</td>
    16                     <td>{{ row.name }}</td>
    17                     <td>
    18                         {% if pagpermission.has_edit %}
    19                          <a href="#">编辑</a>
    20                         {% endif %}
    21                        {% if pagpermission.has_del %}
    22                         <a href="#">删除</a>
    23                        {% endif %}
    24                     </td>
    25                 </tr>
    26             {% endfor %}
    27             </tbody>
    28         </table>
    29 {% endblock %}
    userinfo.html
    1 {% extends "base.html" %}
    2 {% block content %}
    3 <form action="" method="post">
    4     {% csrf_token %}
    5     <p>编号:<input type="text" name="bianhao"></p>
    6     <p>姓名:<input type="text" name="name"></p>
    7     <input type="submit" value="提交">
    8 </form>
    9 {% endblock %}
    userinfo_add.html
     1 {% for k,item in menu_dict.items %}
     2  <div class="item-title">{{ item.menu_title }}</div>
     3      {% if item.active %}
     4             <div class="item-permission">
     5         {% else %}
     6             <div class="item-permission hide">
     7         {% endif %}
     8         {% for v in item.children %}
     9             {% if v.active %}
    10                     <a href="{{ v.url }}" class="active">{{ v.title }}</a>
    11             {% else %}
    12                     <a href="{{ v.url }}">{{ v.title }}</a>
    13             {% endif %}
    14         {% endfor %}
    15     </div>
    16 {% endfor %}
    17 
    18 {# <div class="item-title">菜单一</div>#}
    19 {#        <div class="item-permission">#}
    20 {#            <a href="">用户列表</a>#}
    21 {#            <a href="">订单列表</a>#}
    22 {#        </div>#}
    23 {#    <div class="item-title">菜单二</div>#}
    24 {#        <div class="item-permission hide">#}
    25 {#            <a href="">用户列表</a>#}
    26 {#            <a href="">订单列表</a>#}
    27 {#        </div>#}
    xxxx.html

    9、static---rbac---rbac.css

     1 .left{
     2     float: left;
     3      20%;
     4     height: 500px;
     5     background-color: coral;
     6     padding: 20px 20px;
     7 }
     8 .right{
     9      80%;
    10     height: 500px;
    11     background-color: azure;
    12 }
    13 .item-permission a{
    14     display: block;
    15 }
    16 .hide{
    17     display: none;
    18 }
    19 .item-permission a.active{
    20     color: red;
    21 }
    rbac.css

    10、static---rbac---rbac.js

     1  // 方式一
     2 $(function () {
     3         $(".item-title").click(function () {
     4               $(this).next().toggleClass("hide")
     5         })
     6     });
     7 // 方式二:
     8 //  $(function () {
     9 //     $('.item-title').click(function () {
    10 //         if($(this).next().hasClass('hide')){
    11 //             $(this).next().removeClass('hide')
    12 //         }else{
    13 //             $(this).next().addClass('hide')
    14 //         }
    15 //     })
    16 //  });
    rbac.js
  • 相关阅读:
    发明专利授权容易吗?
    No module named 'PyQt5.QtWebEngineWidgets' 解决方法
    Python可视化界面编程入门
    Python用户界面编程PyQt5的四种的布局方式
    cmd进入任何一个文件夹的步骤?
    cmd如何进入和退出Python编程环境?
    《C++ Primer Plus》16.3 标准模板库 学习笔记
    《C++ Primer Plus》16.2 智能指针模板类
    《C++ Primer Plus》16.1 string类 学习笔记
    Python错误和异常 学习笔记
  • 原文地址:https://www.cnblogs.com/abdm-989/p/14093321.html
Copyright © 2020-2023  润新知