RBAC权限管理
什么是RBAC ?
RBAC
(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,就是权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。
这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便,一般在公司内部使用。
RBAC的表设计
3张表
最开始只有3张表:User表
、Group表
、Permission表
前2张表都通过外键
来和其他表建立联系
5张表
之后分析,User表
和Group表
是多对多
关系,Group表
和Permission表
也是多对多
关系,于是加了2张中间表
:User-Group 表
和Group-Permission 表
,进行了解耦合
6张表
之后,由于某个用户(假设Danny是老板
)需要的权限不在Group表
中,他拥有的是最高权限(所有权限),于是 就产生了第6张中间表:User-Permission 表
Django内置的RBAC的6张表
Django
中所使用的是六表权限,(基本上五表权限就够了),它包含了用户与组的关系,用户与权限的关系(很重要),以及组与权限的关系。
表名 | 释义 |
---|---|
auth_user | 用户表 |
auth_group | 角色表(组表) |
auth_permission | 权限表 |
auth_user_groups | 用户-角色 中间表 |
auth_group_permisssions | 角色-权限 中间表 |
auth_user_user_permissions | 用户-权限 中间表 |
在Django中,分为3种角色:
普通用户
(无法登入后台)工作人员
(可以登入后台)——is_staff
超级管理员
(可以登入后台,拥有所有权限)——is_superuser
使用
自定义
models.py
class User(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
roles = models.ManyToManyField(to='Role')
def __str__(self):
return self.name
class Role(models.Model):
title = models.CharField(max_length=32)
permissions = models.ManyToManyField(to='Permission')
def __str__(self):
return self.title
class Permission(models.Model):
name = models.CharField(max_length=32, verbose_name='权限名称')
url = models.CharField(max_length=32, verbose_name='权限url')
def __str__(self):
return self.name
admin.py
from app01 import models
admin.site.register(models.User, UserConfig)
admin.site.register(models.Role)
admin.site.register(models.Permission)
mypermission.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
import re
class MyPermission(MiddlewareMixin):
def process_request(self, request):
# 定义网站白名单
white_url_list = ['/login/', '/register/', '/admin/.*']
# 1.获取当前用户请求的url
target_url = request.path
# 1.1.先校验是否在白名单中 是则直接放行
for url in white_url_list:
re_path = '^%s$' % url # 将白名单里面的url变成正则表达式 去校验用户访问的url
res = re.search(re_path, target_url)
if res:
return
# 2.获取当前用户的权限列表
permission_list = request.session.get('permission_list')
# 3.判断当前请求url在不在用户可以访问的url列表中
'''也需要改成正则校验的方式'''
# if target_url not in permission_list:
# return HttpResponse("没有权限访问")
for permission in permission_list:
re_path = '^%s$' % permission
res = re.search(re_path, target_url)
if res:
return
return HttpResponse("无法访问,没有权限")
settings.py
# 自定义中间件
MIDDLEWARE = [
'app01.permissions.mypermission.MyPermission'
]
views.py
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user_obj = models.User.objects.filter(name=username,pwd=password).first()
if user_obj:
# 获取当前用户的权限
permission_list = models.User.objects.filter(name=username,pwd=password).values('roles__permissions__url').distinct()
'''由于用户和权限之前是多对多 所以结果集可能会有重复的元素'''
# 存储当前登录用户的权限 便于后续比对
permission_list = [i.get("roles__permissions__url") for i in permission_list]
# print(permission_list)
request.session['permission_list'] = permission_list
return render(request,'login.html')
Django自带
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class UserInfo(AbstractUser):
mobile = models.CharField(max_length=11, unique=True)
class Meta:
verbose_name_plural = '用户信息表'
def __str__(self):
return self.username
admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib import admin
from app_test import models
# 自定义User表后,admin界面管理User类
class UserAdmin(DjangoUserAdmin):
# 添加用户可操作字段
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password', 'is_staff', 'mobile', 'groups', 'user_permissions'),
}),
)
# 展示用户呈现的字段
list_display = ('username', 'mobile', 'is_staff', 'is_active', 'is_superuser')
admin.site.register(models.UserInfo, UserAdmin)
settings.py
AUTH_USER_MODEL = 'app_test.UserInfo'