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     width: 20%;
 4     height: 500px;
 5     background-color: coral;
 6     padding: 20px 20px;
 7 }
 8 .right{
 9     width: 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

 

posted @ 2020-12-06 17:07  ABDM  阅读(139)  评论(0编辑  收藏  举报