├── .gitignore ├── Permisson ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── app01 ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── static │ └── jquery-3.2.1.js ├── tests.py └── views.py ├── db.sqlite3 ├── manage.py ├── rbac ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── middleware │ └── rbac.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20170921_1500.py │ └── __init__.py ├── models.py ├── service │ └── init_permission.py ├── style_script │ ├── rbac.css │ └── rbac.js ├── templates │ └── rbac │ │ ├── common_edit.html │ │ ├── index.html │ │ ├── menus.html │ │ ├── permissions.html │ │ ├── roles.html │ │ └── users.html ├── templatetags │ └── custom_tag.py ├── tests.py ├── urls.py └── views.py └── templates ├── index.html └── login.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | .static_storage/ 56 | .media/ 57 | local_settings.py 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ -------------------------------------------------------------------------------- /Permisson/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/Permisson/__init__.py -------------------------------------------------------------------------------- /Permisson/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for Permisson project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11.4. 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 = 's2#(zr+2@y+2nz*a@q)txe+jjvol^x$z0j74e9yx!zb8&33u3u' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | # DEBUG = False 28 | 29 | ALLOWED_HOSTS = ['*'] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'app01.apps.App01Config', 42 | 'rbac.apps.RbacConfig' 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 'django.middleware.common.CommonMiddleware', 49 | 'django.middleware.csrf.CsrfViewMiddleware', 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | 'django.contrib.messages.middleware.MessageMiddleware', 52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 53 | 'rbac.middleware.rbac.RbacMiddleware' 54 | ] 55 | 56 | ROOT_URLCONF = 'Permisson.urls' 57 | 58 | TEMPLATES = [ 59 | { 60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 61 | 'DIRS': [os.path.join(BASE_DIR, 'templates')] 62 | , 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = 'Permisson.wsgi.application' 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 80 | 81 | DATABASES = { 82 | 'default': { 83 | 'ENGINE': 'django.db.backends.sqlite3', 84 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 85 | } 86 | } 87 | 88 | 89 | # Password validation 90 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 91 | 92 | AUTH_PASSWORD_VALIDATORS = [ 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 104 | }, 105 | ] 106 | 107 | 108 | # Internationalization 109 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 110 | 111 | LANGUAGE_CODE = 'en-us' 112 | 113 | TIME_ZONE = 'UTC' 114 | 115 | USE_I18N = True 116 | 117 | USE_L10N = True 118 | 119 | USE_TZ = True 120 | 121 | 122 | # Static files (CSS, JavaScript, Images) 123 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 124 | 125 | STATIC_URL = '/static/' 126 | STATIC_ROOT = ( 127 | os.path.join(BASE_DIR, '/app01/static'), 128 | ) 129 | 130 | # 定义session 键: 131 | # 保存用户权限url列表 132 | # 保存 权限菜单 和所有 菜单 133 | SESSION_PERMISSION_URL_KEY = 'cool' 134 | 135 | SESSION_MENU_KEY = 'awesome' 136 | ALL_MENU_KEY = 'k1' 137 | PERMISSION_MENU_KEY = 'k2' 138 | 139 | LOGIN_URL = '/login/' 140 | 141 | REGEX_URL = r'^{url}$' # url作严格匹配 142 | 143 | # 配置url权限白名单 144 | SAFE_URL = [ 145 | r'/login/', 146 | '/admin/.*', 147 | '/test/', 148 | '/index/', 149 | '^/rbac/', 150 | ] 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /Permisson/urls.py: -------------------------------------------------------------------------------- 1 | """Permisson URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | from app01 import views 19 | 20 | urlpatterns = [ 21 | url(r'^admin/', admin.site.urls), 22 | url(r'^login/$', views.login), 23 | url(r'^test/$', views.test), 24 | url(r'^index/$', views.index), 25 | url(r'^order/$', views.index), 26 | url(r'^survey/produce/$', views.index), 27 | url(r'^stock/detail/$', views.index), 28 | url(r'^produce/detail/$', views.index), 29 | url(r'^rbac/', include('rbac.urls') ) 30 | ] 31 | -------------------------------------------------------------------------------- /Permisson/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for Permisson project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Permisson.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /app01/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/app01/__init__.py -------------------------------------------------------------------------------- /app01/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /app01/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class App01Config(AppConfig): 5 | name = 'app01' 6 | -------------------------------------------------------------------------------- /app01/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/app01/migrations/__init__.py -------------------------------------------------------------------------------- /app01/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/app01/models.py -------------------------------------------------------------------------------- /app01/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /app01/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect, HttpResponse 2 | from rbac.models import UserInfo 3 | from rbac.service.init_permission import init_permission 4 | from django.conf import settings 5 | 6 | 7 | def login(request): 8 | if request.method == "GET": 9 | return render(request, "login.html") 10 | else: 11 | username = request.POST.get('username') 12 | password = request.POST.get('password') 13 | user_obj = UserInfo.objects.filter(username=username, password=password).first() 14 | if not user_obj: 15 | return render(request, "login.html", {'error': '用户名或密码错误!'}) 16 | else: 17 | init_permission(request, user_obj) 18 | return redirect('/index/') 19 | 20 | 21 | def index(request): 22 | 23 | return render(request, 'index.html') 24 | 25 | 26 | def test(request): 27 | # 前端请求过来,首页显示多级菜单 28 | # 请求过来,拿到session中的信息,拿到菜单,权限数据 -- 定制数据结构 -- 作显示 29 | menu = request.session[settings.SESSION_MENU_KEY] 30 | all_menu = menu[settings.ALL_MENU_KEY] 31 | permission_url = menu[settings.PERMISSION_MENU_KEY] 32 | 33 | print(all_menu) 34 | print('-----------') 35 | print(permission_url) 36 | 37 | all_menu = [ 38 | {'id': 1, 'title': '订单管理', 'parent_id': None}, {'id': 2, 'title': '库存管理', 'parent_id': None}, 39 | {'id': 3, 'title': '生产管理', 'parent_id': None}, {'id': 4, 'title': '生产调查', 'parent_id': None} 40 | ] 41 | 42 | # 定制数据结构 43 | all_menu_dict = {} 44 | for item in all_menu: 45 | item['status'] = False 46 | item['open'] = False 47 | item['children'] = [] 48 | all_menu_dict[item['id']] = item 49 | 50 | all_menu_dict = { 51 | 1: {'id': 1, 'title': '订单管理', 'parent_id': None, 'status': False, 'open': False, 'children': []}, 52 | 2: {'id': 2, 'title': '库存管理', 'parent_id': None, 'status': False, 'open': False, 'children': []}, 53 | 3: {'id': 3, 'title': '生产管理', 'parent_id': None, 'status': False, 'open': False, 'children': []}, 54 | 4: {'id': 4, 'title': '生产调查', 'parent_id': None, 'status': False, 'open': False, 'children': []} 55 | } 56 | 57 | permission_url = [ 58 | {'title': '查看订单', 'url': '/order', 'menu_id': 1}, 59 | {'title': '查看库存清单', 'url': '/stock/detail', 'menu_id': 2}, 60 | {'title': '查看生产订单', 'url': '/produce/detail', 'menu_id': 3}, 61 | {'title': '产出管理', 'url': '/survey/produce', 'menu_id': 4}, 62 | {'title': '工时管理', 'url': '/survey/labor', 'menu_id': 4}, 63 | {'title': '入库', 'url': '/stock/in', 'menu_id': 2}, 64 | {'title': '排单', 'url': '/produce/new', 'menu_id': 3} 65 | ] 66 | 67 | request_rul = '/stock/in' 68 | import re 69 | 70 | for url in permission_url: 71 | # 添加两个状态:显示 和 展开 72 | url['status'] = True 73 | pattern = url['url'] 74 | if re.match(pattern, request_rul): 75 | url['open'] = True 76 | else: 77 | url['open'] = False 78 | 79 | # 将url添加到菜单下 80 | all_menu_dict[url['menu_id']]["children"].append(url) 81 | 82 | # 显示菜单:url 的菜单及上层菜单 status: true 83 | pid = url['menu_id'] 84 | while pid: 85 | all_menu_dict[pid]['status'] = True 86 | pid = all_menu_dict[pid]['parent_id'] 87 | 88 | # 展开url上层菜单:url['open'] = True, 其菜单及其父菜单open = True 89 | if url['open']: 90 | ppid = url['menu_id'] 91 | while ppid: 92 | all_menu_dict[ppid]['open'] = True 93 | ppid = all_menu_dict[ppid]['parent_id'] 94 | 95 | # 整理菜单层级结构:没有parent_id 的为根菜单, 并将有parent_id 的菜单项加入其父项的chidren内 96 | final_menu = [] 97 | for i in all_menu_dict: 98 | if all_menu_dict[i]['parent_id']: 99 | pid = all_menu_dict[i]['parent_id'] 100 | parent_menu = all_menu_dict[pid] 101 | parent_menu['children'].append(all_menu_dict[i]) 102 | else: 103 | final_menu.append(all_menu_dict[i]) 104 | 105 | print('final_menu ---------------\n',final_menu) 106 | 107 | 108 | return HttpResponse('...') 109 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/db.sqlite3 -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Permisson.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /rbac/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/rbac/__init__.py -------------------------------------------------------------------------------- /rbac/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Menu, Permission, Role, UserInfo 3 | 4 | # Register your models here. 5 | admin.site.register(Menu) 6 | admin.site.register(Permission) 7 | admin.site.register(Role) 8 | admin.site.register(UserInfo) -------------------------------------------------------------------------------- /rbac/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class RbacConfig(AppConfig): 5 | name = 'rbac' 6 | -------------------------------------------------------------------------------- /rbac/forms.py: -------------------------------------------------------------------------------- 1 | from django.forms import ModelForm 2 | from .models import UserInfo, Role, Permission, Menu 3 | 4 | 5 | class UserInfoModelForm(ModelForm): 6 | class Meta: 7 | model = UserInfo 8 | fields = '__all__' 9 | labels = { 10 | 'username': '用户名', 11 | 'password': '密码', 12 | 'nickname': '昵称', 13 | 'email': '邮箱', 14 | 'roles': '角色', 15 | } 16 | 17 | 18 | class RoleModelForm(ModelForm): 19 | class Meta: 20 | model = Role 21 | fields = '__all__' 22 | labels = { 23 | 'title': '角色', 24 | 'permissions': '权限', 25 | } 26 | 27 | 28 | class PermissionModelForm(ModelForm): 29 | class Meta: 30 | model = Permission 31 | fields = '__all__' 32 | labels = { 33 | 'title': '权限', 34 | 'url': 'url', 35 | 'menu': '所属菜单' 36 | } 37 | 38 | 39 | class MenuModelForm(ModelForm): 40 | class Meta: 41 | model = Menu 42 | fields = '__all__' 43 | labels = { 44 | 'title': '菜单', 45 | 'parent': '父级菜单', 46 | } 47 | -------------------------------------------------------------------------------- /rbac/middleware/rbac.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.shortcuts import HttpResponse, redirect 3 | import re 4 | 5 | 6 | class MiddlewareMixin(object): 7 | def __init__(self, get_response=None): 8 | self.get_response = get_response 9 | super(MiddlewareMixin, self).__init__() 10 | 11 | def __call__(self, request): 12 | response = None 13 | if hasattr(self, 'process_request'): 14 | response = self.process_request(request) 15 | if not response: 16 | response = self.get_response(request) 17 | if hasattr(self, 'process_response'): 18 | response = self.process_response(request, response) 19 | return response 20 | 21 | 22 | class RbacMiddleware(MiddlewareMixin): 23 | """ 24 | 检查用户的url请求是否是其权限范围内 25 | """ 26 | def process_request(self, request): 27 | request_url = request.path_info 28 | permission_url = request.session.get(settings.SESSION_PERMISSION_URL_KEY) 29 | print('访问url',request_url) 30 | print('权限--',permission_url) 31 | # 如果请求url在白名单,放行 32 | for url in settings.SAFE_URL: 33 | if re.match(url, request_url): 34 | return None 35 | 36 | # 如果未取到permission_url, 重定向至登录;为了可移植性,将登录url写入配置 37 | # 另外,Login必须设置白名单,否则访问login会反复重定向 38 | if not permission_url: 39 | return redirect(settings.LOGIN_URL) 40 | 41 | # 循环permission_url,作为正则,匹配用户request_url 42 | # 正则应该进行一些限定,以处理:/user/ -- /user/add/匹配成功的情况 43 | flag = False 44 | for url in permission_url: 45 | url_pattern = settings.REGEX_URL.format(url=url) 46 | if re.match(url_pattern, request_url): 47 | flag = True 48 | break 49 | if flag: 50 | return None 51 | else: 52 | # 如果是调试模式,显示可访问url 53 | if settings.DEBUG: 54 | info ='
' + ( '
'.join(permission_url)) 55 | return HttpResponse('无权限,请尝试访问以下地址:%s' %info) 56 | else: 57 | return HttpResponse('无权限访问') 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /rbac/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.4 on 2017-09-21 05:10 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Menu', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('title', models.CharField(max_length=32, unique=True)), 22 | ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='rbac.Menu')), 23 | ], 24 | ), 25 | migrations.CreateModel( 26 | name='Permission', 27 | fields=[ 28 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 29 | ('title', models.CharField(max_length=32, unique=True)), 30 | ('url', models.CharField(max_length=128, unique=True)), 31 | ('menu', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='rbac.Menu')), 32 | ], 33 | ), 34 | migrations.CreateModel( 35 | name='Role', 36 | fields=[ 37 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 38 | ('title', models.CharField(max_length=32, unique=True)), 39 | ('permissions', models.ManyToManyField(to='rbac.Permission')), 40 | ], 41 | ), 42 | migrations.CreateModel( 43 | name='UserInfo', 44 | fields=[ 45 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 46 | ('username', models.CharField(max_length=32)), 47 | ('password', models.CharField(max_length=64)), 48 | ('nickname', models.CharField(max_length=32)), 49 | ('email', models.EmailField(max_length=254)), 50 | ('role', models.ManyToManyField(to='rbac.Role')), 51 | ], 52 | ), 53 | ] 54 | -------------------------------------------------------------------------------- /rbac/migrations/0002_auto_20170921_1500.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.4 on 2017-09-21 07:00 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('rbac', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='userinfo', 17 | old_name='role', 18 | new_name='roles', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /rbac/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayhan-Huang/RBAC/fad0a56ca4d0f45cb9354c050364b6d017bf67fc/rbac/migrations/__init__.py -------------------------------------------------------------------------------- /rbac/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Menu(models.Model): 5 | """ 6 | 菜单 7 | """ 8 | title = models.CharField(max_length=32, unique=True) 9 | parent = models.ForeignKey("Menu", null=True, blank=True) 10 | # 定义菜单间的自引用关系 11 | # 权限url 在 菜单下;菜单可以有父级菜单;还要支持用户创建菜单,因此需要定义parent字段(parent_id) 12 | # blank=True 意味着在后台管理中填写可以为空,根菜单没有父级菜单 13 | 14 | def __str__(self): 15 | # 显示层级菜单 16 | title_list = [self.title] 17 | p = self.parent 18 | while p: 19 | title_list.insert(0, p.title) 20 | p = p.parent 21 | return '-'.join(title_list) 22 | 23 | 24 | class Permission(models.Model): 25 | """ 26 | 权限 27 | """ 28 | title = models.CharField(max_length=32, unique=True) 29 | url = models.CharField(max_length=128, unique=True) 30 | menu = models.ForeignKey("Menu", null=True, blank=True) 31 | 32 | def __str__(self): 33 | # 显示带菜单前缀的权限 34 | return '{menu}---{permission}'.format(menu=self.menu, permission=self.title) 35 | 36 | 37 | class Role(models.Model): 38 | """ 39 | 角色:绑定权限 40 | """ 41 | title = models.CharField(max_length=32, unique=True) 42 | 43 | permissions = models.ManyToManyField("Permission") 44 | # 定义角色和权限的多对多关系 45 | 46 | def __str__(self): 47 | return self.title 48 | 49 | 50 | class UserInfo(models.Model): 51 | """ 52 | 用户:划分角色 53 | """ 54 | username = models.CharField(max_length=32) 55 | password = models.CharField(max_length=64) 56 | nickname = models.CharField(max_length=32) 57 | email = models.EmailField() 58 | 59 | roles = models.ManyToManyField("Role") 60 | # 定义用户和角色的多对多关系 61 | 62 | def __str__(self): 63 | return self.nickname 64 | 65 | 66 | ''' 继承自带的用户表 67 | 68 | settings.py: 69 | AUTH_USER_MODEL = 'rbac.User' 70 | 71 | from django.contrib.auth.models import AbstractUser 72 | 73 | class User(AbstractUser): 74 | """ 75 | 用户:划分角色 76 | """ 77 | username = models.CharField(verbose_name='用户', max_length=32, unique=True) 78 | 79 | roles = models.ManyToManyField(verbose_name='角色', to="Role") 80 | # 定义用户和角色的多对多关系 81 | 82 | def __str__(self): 83 | return self.username 84 | 85 | ''' 86 | 87 | 88 | -------------------------------------------------------------------------------- /rbac/service/init_permission.py: -------------------------------------------------------------------------------- 1 | from ..models import UserInfo, Menu 2 | 3 | 4 | def init_permission(request, user_obj): 5 | """ 6 | 初始化用户权限, 写入session 7 | :param request: 8 | :param user_obj: 9 | :return: 10 | """ 11 | permission_item_list = user_obj.roles.values('permissions__url', 12 | 'permissions__title', 13 | 'permissions__menu_id').distinct() 14 | # print(permission_menu_list) 15 | permission_url_list = [] # 用户权限url列表,--> 用于中间件验证用户权限 16 | permission_menu_list = [] # 用户权限url所属菜单列表 [{"title":xxx, "url":xxx, "menu_id": xxx},{},] 17 | 18 | for item in permission_item_list: 19 | permission_url_list.append(item['permissions__url']) 20 | if item['permissions__menu_id']: 21 | temp = {"title": item['permissions__title'], 22 | "url": item["permissions__url"], 23 | "menu_id": item["permissions__menu_id"]} 24 | permission_menu_list.append(temp) 25 | 26 | menu_list = list(Menu.objects.values('id', 'title', 'parent_id')) 27 | # 注:session在存储时,会先对数据进行序列化,因此对于Queryset对象写入session, 加list()转为可序列化对象 28 | 29 | from django.conf import settings 30 | 31 | # 保存用户权限url列表 32 | print('permission_url_list ------------------- ',permission_url_list) 33 | print('permission_menu_list ------------------- ',permission_menu_list) 34 | print('menu_list ------------------- ',menu_list) 35 | 36 | request.session[settings.SESSION_PERMISSION_URL_KEY] = permission_url_list 37 | 38 | # 保存 权限菜单 和所有 菜单 39 | request.session[settings.SESSION_MENU_KEY] = { 40 | settings.ALL_MENU_KEY: menu_list, 41 | settings.PERMISSION_MENU_KEY: permission_menu_list, 42 | } 43 | 44 | print('request.session[settings.SESSION_PERMISSION_URL_KEY] ------------------- ', request.session[settings.SESSION_PERMISSION_URL_KEY]) 45 | -------------------------------------------------------------------------------- /rbac/style_script/rbac.css: -------------------------------------------------------------------------------- 1 | 2 | .rbac-hide { 3 | display: none; 4 | } 5 | 6 | .rbac-menu-item .rbac-menu-body { 7 | margin-left: 20px; 8 | } 9 | 10 | .rbac-menu-body a { 11 | display: block; 12 | } 13 | 14 | .rbac-menu-body a.rbac-active { 15 | color: red; 16 | } 17 | -------------------------------------------------------------------------------- /rbac/style_script/rbac.js: -------------------------------------------------------------------------------- 1 | $('.rbac-menu-header').click(function () { 2 | $(this).next().toggleClass('rbac-hide'); 3 | //$(this).next().removeClass('rbac-hide').parent().siblings().find('.rbac-menu-body').addClass('rbac-hide'); 4 | }); -------------------------------------------------------------------------------- /rbac/templates/rbac/common_edit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 |

{{ title }}

9 |
10 | {% csrf_token %} 11 | {{ model_form.as_p }} 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /rbac/templates/rbac/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 |

菜单管理

10 |

角色管理

11 |

权限管理

12 |

用户管理

13 | 14 | 15 | -------------------------------------------------------------------------------- /rbac/templates/rbac/menus.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for menu in menu_list %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% endfor %} 24 |
菜单父级菜单操作
{{ menu.title }}{{ menu.parent }}编辑删除
25 | 26 | 27 | -------------------------------------------------------------------------------- /rbac/templates/rbac/permissions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for permission in permission_list %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% endfor %} 26 |
权限url所属菜单操作
{{ permission.title }}{{ permission.url }}{{ permission.menu }}编辑删除
27 | 28 | 29 | -------------------------------------------------------------------------------- /rbac/templates/rbac/roles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for role in role_list %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% endfor %} 24 |
角色权限操作
{{ role.title }}{{ role.permissions.all }}编辑删除
25 | 26 | 27 | -------------------------------------------------------------------------------- /rbac/templates/rbac/users.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% for user in user_list %} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% endfor %} 30 |
用户名密码昵称邮件角色操作
{{ user.username }}{{ user.password }}{{ user.nickname }}{{ user.email }}{{ user.roles.all }}编辑删除
31 | 32 | 33 | -------------------------------------------------------------------------------- /rbac/templatetags/custom_tag.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.conf import settings 3 | import re, os 4 | from django.utils.safestring import mark_safe 5 | 6 | register = template.Library() 7 | 8 | 9 | def get_structure_data(request): 10 | """处理菜单结构""" 11 | menu = request.session[settings.SESSION_MENU_KEY] 12 | all_menu = menu[settings.ALL_MENU_KEY] 13 | permission_url = menu[settings.PERMISSION_MENU_KEY] 14 | 15 | # all_menu = [ 16 | # {'id': 1, 'title': '订单管理', 'parent_id': None}, 17 | # {'id': 2, 'title': '库存管理', 'parent_id': None}, 18 | # {'id': 3, 'title': '生产管理', 'parent_id': None}, 19 | # {'id': 4, 'title': '生产调查', 'parent_id': None} 20 | # ] 21 | 22 | # 定制数据结构 23 | all_menu_dict = {} 24 | for item in all_menu: 25 | item['status'] = False 26 | item['open'] = False 27 | item['children'] = [] 28 | all_menu_dict[item['id']] = item 29 | 30 | # all_menu_dict = { 31 | # 1: {'id': 1, 'title': '订单管理', 'parent_id': None, 'status': False, 'open': False, 'children': []}, 32 | # 2: {'id': 2, 'title': '库存管理', 'parent_id': None, 'status': False, 'open': False, 'children': []}, 33 | # 3: {'id': 3, 'title': '生产管理', 'parent_id': None, 'status': False, 'open': False, 'children': []}, 34 | # 4: {'id': 4, 'title': '生产调查', 'parent_id': None, 'status': False, 'open': False, 'children': []} 35 | # } 36 | 37 | # permission_url = [ 38 | # {'title': '查看订单', 'url': '/order', 'menu_id': 1}, 39 | # {'title': '查看库存清单', 'url': '/stock/detail', 'menu_id': 2}, 40 | # {'title': '查看生产订单', 'url': '/produce/detail', 'menu_id': 3}, 41 | # {'title': '产出管理', 'url': '/survey/produce', 'menu_id': 4}, 42 | # {'title': '工时管理', 'url': '/survey/labor', 'menu_id': 4}, 43 | # {'title': '入库', 'url': '/stock/in', 'menu_id': 2}, 44 | # {'title': '排单', 'url': '/produce/new', 'menu_id': 3} 45 | # ] 46 | 47 | request_rul = request.path_info 48 | 49 | for url in permission_url: 50 | # 添加两个状态:显示 和 展开 51 | url['status'] = True 52 | pattern = url['url'] 53 | if re.match(pattern, request_rul): 54 | url['open'] = True 55 | else: 56 | url['open'] = False 57 | 58 | # 将url添加到菜单下 59 | all_menu_dict[url['menu_id']]["children"].append(url) 60 | 61 | # 显示菜单:url 的菜单及上层菜单 status: true 62 | pid = url['menu_id'] 63 | while pid: 64 | all_menu_dict[pid]['status'] = True 65 | pid = all_menu_dict[pid]['parent_id'] 66 | 67 | # 展开url上层菜单:url['open'] = True, 其菜单及其父菜单open = True 68 | if url['open']: 69 | ppid = url['menu_id'] 70 | while ppid: 71 | all_menu_dict[ppid]['open'] = True 72 | ppid = all_menu_dict[ppid]['parent_id'] 73 | 74 | # 整理菜单层级结构:没有parent_id 的为根菜单, 并将有parent_id 的菜单项加入其父项的chidren内 75 | menu_data = [] 76 | for i in all_menu_dict: 77 | if all_menu_dict[i]['parent_id']: 78 | pid = all_menu_dict[i]['parent_id'] 79 | parent_menu = all_menu_dict[pid] 80 | parent_menu['children'].append(all_menu_dict[i]) 81 | else: 82 | menu_data.append(all_menu_dict[i]) 83 | 84 | return menu_data 85 | 86 | 87 | def get_menu_html(menu_data): 88 | """显示:菜单 + [子菜单] + 权限(url)""" 89 | option_str = """ 90 |
91 |
92 | 93 | {menu_title}
94 |
{sub_menu}
95 |
96 | """ 97 | 98 | url_str = """ 99 | {permission_title} 100 | """ 101 | 102 | """ 103 | menu_data = [ 104 | {'id': 1, 'title': '订单管理', 'parent_id': None, 'status': True, 'open': False, 105 | 'children': [{'title': '查看订单', 'url': '/order', 'menu_id': 1, 'status': True, 'open': False}]}, 106 | {'id': 2, 'title': '库存管理', 'parent_id': None, 'status': True, 'open': True, 107 | 'children': [{'title': '查看库存清单', 'url': '/stock/detail', 'menu_id': 2, 'status': True, 'open': False}, 108 | {'title': '入库', 'url': '/stock/in', 'menu_id': 2, 'status': True, 'open': True}]}, 109 | {'id': 3, 'title': '生产管理', 'parent_id': None, 'status': True, 'open': False, 110 | 'children': [{'title': '查看生产订单', 'url': '/produce/detail', 'menu_id': 3, 'status': True, 'open': False}, 111 | {'title': '排单', 'url': '/produce/new', 'menu_id': 3, 'status': True, 'open': False}]}, 112 | {'id': 4, 'title': '生产调查', 'parent_id': None, 'status': True, 'open': False, 113 | 'children': [{'title': '产出管理', 'url': '/survey/produce', 'menu_id': 4, 'status': True, 'open': False}, 114 | {'title': '工时管理', 'url': '/survey/labor', 'menu_id': 4, 'status': True, 'open': False}]} 115 | ] 116 | """ 117 | 118 | menu_html = '' 119 | for item in menu_data: 120 | if not item['status']: # 如果用户权限不在某个菜单下,即item['status']=False, 不显示 121 | continue 122 | else: 123 | if item.get('url'): # 说明循环到了菜单最里层的url 124 | menu_html += url_str.format(permission_url=item['url'], 125 | active="rbac-active" if item['open'] else "", 126 | permission_title=item['title']) 127 | else: 128 | if item.get('children'): 129 | sub_menu = get_menu_html(item['children']) 130 | else: 131 | sub_menu = "" 132 | 133 | menu_html += option_str.format(menu_title=item['title'], 134 | sub_menu=sub_menu, 135 | display="" if item['open'] else "rbac-hide", 136 | status="open" if item['open'] else "close") 137 | 138 | return menu_html 139 | 140 | 141 | @register.simple_tag 142 | def rbac_menu(request): 143 | """ 144 | 显示多级菜单:请求过来 -- 拿到session中的菜单,权限数据 -- 处理数据 -- 作显示 145 | 返回多级菜单:数据处理部分抽象出来由单独的函数处理;渲染部分也抽象出来由单独函数处理 146 | :param request: 147 | :return: 148 | """ 149 | menu_data = get_structure_data(request) 150 | menu_html = get_menu_html(menu_data) 151 | 152 | return mark_safe(menu_html) 153 | # 因为标签无法使用safe过滤器,这里用mark_safe函数来实现 154 | 155 | 156 | @register.simple_tag 157 | def rbac_css(): 158 | """ 159 | rabc要用到的css文件路径,并读取返回;注意返回字符串用mark_safe,否则传到模板会转义 160 | :return: 161 | """ 162 | css_path = os.path.join('rbac', 'style_script','rbac.css') 163 | css = open(css_path,'r',encoding='utf-8').read() 164 | return mark_safe(css) 165 | 166 | 167 | @register.simple_tag 168 | def rbac_js(): 169 | """ 170 | rabc要用到的js文件路径,并读取返回 171 | :return: 172 | """ 173 | js_path = os.path.join('rbac', 'style_script', 'rbac.js') 174 | js = open(js_path, 'r', encoding='utf-8').read() 175 | return mark_safe(js) 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /rbac/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | 5 | all_menu_dict = { 6 | 1: {'id': 1, 'caption': '用户管理', 'parent_id': None, "children": [], "status": False, "open": False}, 7 | 2: {'id': 2, 'caption': '订单管理', 'parent_id': None, "children": [], "status": False, "open": False}, 8 | 3: {'id': 3, 'caption': '其他', 'parent_id': None, "children": [], "status": False, "open": False}, 9 | 4: {'id': 4, 'caption': '退货', 'parent_id': 2, "children": [], "status": True, "open": False}, 10 | 5: {'id': 5, 'caption': '换货', 'parent_id': 2, "children": [], "status": False, "open": False} 11 | } 12 | 13 | permisson_url = [ 14 | {'title': '权限1', 'url': '/test/', 'menu_id': 1}, 15 | {'title': '权限2', 'url': '/test/', 'menu_id': 1}, 16 | {'title': '权限3', 'url': '/login', 'menu_id': 4}, 17 | {'title': '权限4', 'url': '/test/', 'menu_id': 5} 18 | ] 19 | 20 | request_rul = '/login' 21 | import re 22 | 23 | for url in permisson_url: 24 | # 添加两个状态:显示 和 展开 25 | url['status'] = True 26 | pattern = url['url'] 27 | if re.match(pattern, request_rul): 28 | url['open'] = True 29 | else: 30 | url['open'] = False 31 | 32 | # 将url添加到菜单下 33 | all_menu_dict[url['menu_id']]["children"].append(url) 34 | 35 | # 显示菜单:url 的菜单及上层菜单 status: true 36 | pid = url['menu_id'] 37 | while pid: 38 | all_menu_dict[pid]['status'] = True 39 | pid = all_menu_dict[pid]['parent_id'] 40 | 41 | # 展开url上层菜单:url['open'] = True, 其菜单及其父菜单open = True 42 | if url['open']: 43 | ppid = url['menu_id'] 44 | while ppid: 45 | all_menu_dict[ppid]['open'] = True 46 | ppid = all_menu_dict[ppid]['parent_id'] 47 | 48 | 49 | 50 | 51 | 52 | print(all_menu_dict) 53 | 54 | -------------------------------------------------------------------------------- /rbac/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from . import views 3 | 4 | urlpatterns = [ 5 | url(r'^users/$', views.users), 6 | url(r'^users/new/$', views.users_new), 7 | url(r'^users/edit/(?P\d+)/$', views.users_edit), 8 | url(r'^users/delete/(?P\d+)/$', views.users_delete), 9 | 10 | url(r'^roles/$', views.roles), 11 | url(r'^roles/new/$', views.roles_new), 12 | url(r'^roles/edit/(?P\d+)/$', views.roles_edit), 13 | url(r'^roles/delete/(?P\d+)/$', views.roles_delete), 14 | 15 | url(r'^permissions/$', views.permissions), 16 | url(r'^permissions/new/$', views.permissions_new), 17 | url(r'^permissions/edit/(?P\d+)/$', views.permissions_edit), 18 | url(r'^permissions/delete/(?P\d+)/$', views.permissions_delete), 19 | 20 | url(r'^menus/$', views.menus), 21 | url(r'^menus/new/$', views.menus_new), 22 | url(r'^menus/edit/(?P\d+)/$', views.menus_edit), 23 | url(r'^menus/delete/(?P\d+)/$', views.menus_delete), 24 | 25 | url(r'^$', views.index) 26 | ] 27 | -------------------------------------------------------------------------------- /rbac/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect, reverse 2 | from .models import UserInfo, Role, Permission, Menu 3 | from .forms import UserInfoModelForm, RoleModelForm, PermissionModelForm, MenuModelForm 4 | 5 | 6 | def index(request): 7 | return render(request, 'rbac/index.html') 8 | 9 | 10 | def users(request): 11 | """查询所有用户信息""" 12 | user_list = UserInfo.objects.all() 13 | return render(request, 'rbac/users.html', {'user_list': user_list}) 14 | 15 | 16 | def users_new(request): 17 | if request.method =="GET": 18 | # 传入ModelForm对象 19 | model_form = UserInfoModelForm() 20 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增用户'}) 21 | else: 22 | model_form = UserInfoModelForm(request.POST) 23 | if model_form.is_valid(): 24 | model_form.save() 25 | return redirect(reverse(users)) 26 | else: 27 | return render(request, 'rbac/common_edit.html',{'model_form': model_form, 'title': '新增用户'}) 28 | 29 | 30 | def users_edit(request,id): 31 | user_obj = UserInfo.objects.filter(id=id).first() 32 | if request.method == 'GET': 33 | model_form = UserInfoModelForm(instance=user_obj) 34 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑用户'}) 35 | else: 36 | model_form = UserInfoModelForm(request.POST, instance=user_obj) 37 | if model_form.is_valid(): 38 | model_form.save() 39 | return redirect(reverse(users)) 40 | else: 41 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑用户'}) 42 | 43 | 44 | def users_delete(request, id): 45 | user_obj = UserInfo.objects.filter(id=id).first() 46 | user_obj.delete() 47 | return redirect(reverse(users)) 48 | 49 | 50 | def roles(request): 51 | role_list = Role.objects.all() 52 | return render(request, 'rbac/roles.html', {'role_list': role_list}) 53 | 54 | 55 | def roles_new(request): 56 | if request.method == "GET": 57 | # 传入ModelForm对象 58 | model_form = RoleModelForm() 59 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增角色'}) 60 | else: 61 | model_form = RoleModelForm(request.POST) 62 | if model_form.is_valid(): 63 | model_form.save() 64 | return redirect(reverse(roles)) 65 | else: 66 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增角色'}) 67 | 68 | 69 | def roles_edit(request, id): 70 | role_obj = Role.objects.filter(id=id).first() 71 | if request.method == 'GET': 72 | model_form = RoleModelForm(instance=role_obj) 73 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑角色'}) 74 | else: 75 | model_form = RoleModelForm(request.POST, instance=role_obj) 76 | if model_form.is_valid(): 77 | model_form.save() 78 | return redirect(reverse(roles)) 79 | else: 80 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑角色'}) 81 | 82 | 83 | def roles_delete(request, id): 84 | role_obj = Role.objects.filter(id=id).first() 85 | role_obj.delete() 86 | return redirect(reverse(roles)) 87 | 88 | 89 | def permissions(request): 90 | permission_list = Permission.objects.all() 91 | return render(request, 'rbac/permissions.html', {'permission_list': permission_list}) 92 | 93 | 94 | def permissions_new(request): 95 | if request.method == "GET": 96 | # 传入ModelForm对象 97 | model_form = PermissionModelForm() 98 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增权限'}) 99 | else: 100 | model_form = PermissionModelForm(request.POST) 101 | if model_form.is_valid(): 102 | model_form.save() 103 | return redirect(reverse(permissions)) 104 | else: 105 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增权限'}) 106 | 107 | 108 | def permissions_edit(request, id): 109 | permission_obj = Permission.objects.filter(id=id).first() 110 | if request.method == 'GET': 111 | model_form = PermissionModelForm(instance=permission_obj) 112 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑权限'}) 113 | else: 114 | model_form = PermissionModelForm(request.POST, instance=permission_obj) 115 | if model_form.is_valid(): 116 | model_form.save() 117 | return redirect(reverse(permissions)) 118 | else: 119 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑权限'}) 120 | 121 | 122 | def permissions_delete(request, id): 123 | permission_obj = Role.objects.filter(id=id).first() 124 | permission_obj.delete() 125 | return redirect(reverse(permissions)) 126 | 127 | 128 | def menus(request): 129 | menu_list = Menu.objects.all() 130 | return render(request, 'rbac/menus.html', {'menu_list': menu_list}) 131 | 132 | 133 | def menus_new(request): 134 | if request.method == "GET": 135 | # 传入ModelForm对象 136 | model_form = MenuModelForm() 137 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增菜单'}) 138 | else: 139 | model_form = MenuModelForm(request.POST) 140 | if model_form.is_valid(): 141 | model_form.save() 142 | return redirect(reverse(menus)) 143 | else: 144 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '新增菜单'}) 145 | 146 | 147 | def menus_edit(request, id): 148 | menu_obj = Menu.objects.filter(id=id).first() 149 | if request.method == 'GET': 150 | model_form = MenuModelForm(instance=menu_obj) 151 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑菜单'}) 152 | else: 153 | model_form = MenuModelForm(request.POST, instance=menu_obj) 154 | if model_form.is_valid(): 155 | model_form.save() 156 | return redirect(reverse(menus)) 157 | else: 158 | return render(request, 'rbac/common_edit.html', {'model_form': model_form, 'title': '编辑菜单'}) 159 | 160 | 161 | def menus_delete(request, id): 162 | menu_obj = Role.objects.filter(id=id).first() 163 | menu_obj.delete() 164 | return redirect(reverse(menus)) 165 | 166 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% load custom_tag %} 2 | {% load static %} 3 | 4 | 5 | 6 | 7 | Title 8 | {# 通过调用自定义标签中的函数,导入rbac中的css和js #} 9 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | {% rbac_menu request %} 23 | 24 | 25 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 |
10 | {% csrf_token %} 11 |

用户名:

12 | 13 |

密码:

14 | 15 |

16 |  {{ error }} 17 |

18 |
19 | 20 | 21 | --------------------------------------------------------------------------------