一、model模块


权限表结构设计:

rbac基于角色的权限管理开发_权限管理

from django.db import models


class User(models.Model):
"""
用户表
"""
username = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
email = models.EmailField(verbose_name='邮箱')

def __str__(self):
return self.username


class Role(models.Model):
"""
角色表
"""
caption = models.CharField(verbose_name='角色', max_length=32)

def __str__(self):
return self.caption


class User2Role(models.Model):
"""
用户角色关系表
"""
user = models.ForeignKey(User, verbose_name='用户', related_name='roles',on_delete='')
role = models.ForeignKey(Role, verbose_name='角色', related_name='users',on_delete='')

def __str__(self):
return '%s-%s' % (self.user.username, self.role.caption,)


class Menu(models.Model):
"""
菜单表
"""
caption = models.CharField(verbose_name='菜单名称', max_length=32)
parent = models.ForeignKey('self', verbose_name='父菜单', related_name='p', null=True, blank=True,on_delete='')

def __str__(self):
prev = ""
parent = self.parent
while True:
if parent:
prev = prev + '-' + str(parent.caption)
parent = parent.parent
else:
break
return '%s-%s' % (prev, self.caption,)


class Permission(models.Model):
"""
权限
"""
caption = models.CharField(verbose_name='权限', max_length=32)
url = models.CharField(verbose_name='URL正则', max_length=128)
menu = models.ForeignKey(Menu, verbose_name='所属菜单', related_name='permissions',null=True,blank=True,on_delete='')

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


class Action(models.Model):
"""
操作:增删改查
"""
caption = models.CharField(verbose_name='操作标题', max_length=32)
code = models.CharField(verbose_name='方法', max_length=32)

def __str__(self):
return self.caption


class Permission2Action2Role(models.Model):
"""
权限操作关系表
"""
permission = models.ForeignKey(Permission, verbose_name='权限URL', related_name='actions',on_delete='')
action = models.ForeignKey(Action, verbose_name='操作', related_name='permissions',on_delete='')
role = models.ForeignKey(Role, verbose_name='角色', related_name='p2as',on_delete='')

class Meta:
unique_together = (
('permission', 'action', 'role'),
)

def __str__(self):
return "%s-%s-%s"

二、urls.py模块


urlpatterns = [
path('admin/', admin.site.urls),
url(r'^auth-login.html$', views2.login),
url(r'^auth-index(-\d+)*.html$', views2.index),
]

三、views.py模块


from django.shortcuts import render,redirect,HttpResponse
from app02 import models

# Create your views here.
def login(request):
if request.method == 'GET':
return render(request, 'login2.html')
else:
# # 根据用户登录信息获得所有权限
# object = models.User.objects.filter(username='tom').first() # 假定根据登陆信息获得用户名为tom
# # 根据用户对象获得对应的所有角色(有2种方式)
# role_list = models.User2Role.objects.filter(user_id=object.id) # 方式一:正向操作 获得[User2Role,User2Role,User2Role]
# # 方式二:反向操作,通过users跨表到user表中的user_id字段,获得对应的role表的所有id,从而获得所有role(推荐该方法)
# role_list = models.Role.objects.filter(users__user_id=object.id)
#
# # 根据角色对象,获得所有权限,并去重
# from django.db.models import Count
# # models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url', 'action__code').annotate(c = Count('id'))
# # 推荐下面方式,不会生成新的字段c
# permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url', 'action__code').distinct()
# # 获得结果如下所示:
# """
# [
# {permission_url: '/index.html', action_code:'GET'},
# {permission_url: '/index.html', action_code:'POST'},
# {permission_url: '/index.html', action_code:'DEL'},
# {permission_url: '/index.html', action_code:'Edit'},
# {permission_url: '/order.html', action_code:'GET'},
# {permission_url: '/order.html', action_code:'POST'},
# {permission_url: '/order.html', action_code:'DEL'},
# {permission_url: '/order.html', action_code:'Edit'},
# ]
# """
# 再通过for循环将数据库中查出的数据转换成如下格式:
user_permission_dict = {
'/ah-index.html': ["GET","POST","DEL","Edit"],
'/order.html': ["GET","POST","DEL","Edit"],
'/auth-index(-\d+)*.html': ["GET","POST","DEL","Edit"], # 可接收通过格式 '/auth-index-3.html', '/auth-index.html'
}

# 将用户的对应的权限放入session中,当访问其它链接时,可直接从session中进行校验是否存在该权限
request.session['user_permission_dict'] = user_permission_dict
return HttpResponse('登陆成功')

def index(request):
return HttpResponse('登陆成功,你拥有了权限,恭喜你看见了我')

三、html模版


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="/auth-login.html">{% csrf_token<input type="text" name="user/">
<input type="submit" value="提交/">
</form>
</body>
</html>

四、自定义中间件


# 添加中间件,控制权限
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
import re
class M1(MiddlewareMixin):
def process_request(self, request, **kwargs):
valid = ['/auth-login.html', '/index.html'] # 设置白名单,不进行校验
if request.path_info not in valid: # /auth-index
action = request.GET.get('md') # 获得操作指令
user_permission_dict = request.session.get['user_permission_dict'] # 获得权限字典
if not user_permission_dict:
return HttpResponse('无权限')

flag = False
if request.path_info != '/favicon.ico': # 每一次请求,request.path_info会获得两个值,请求url和/favicon
for k, v in user_permission_dict.items():
if re.match(k, request.path_info): # 正则匹配,假定数据库的为/index-(\d+).html,则/auth-index-3.html等格式可同样包括
if action in v:
flag = True # 表示该用户拥有该权限操作,继续往下执行
break
if not flag:
return HttpResponse('无权限')

六、setting.py模块


MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'middleware.md.M1', # 将该中间件注册