django-权限管理
第一步
#创建表
from django.db import models
class Permission(models.Model):
"""
权限表
"""
title = models.CharField(verbose_name=\'标题\',max_length=32)
url = models.CharField(verbose_name="含正则URL",max_length=64)
is_menu = models.BooleanField(verbose_name="是否是菜单")
class Meta:
verbose_name_plural = "权限表" #添加表到后台中去
def __str__(self):
return self.title
class User(models.Model):
"""
用户表
"""
username = models.CharField(verbose_name=\'用户名\',max_length=32) #verbose_name将在后台页面上显示自定义的名字
password = models.CharField(verbose_name=\'密码\',max_length=64)
email = models.CharField(verbose_name=\'邮箱\',max_length=32)
roles = models.ManyToManyField(verbose_name=\'具有的所有角色\',to="Role",blank=True)
class Meta:
verbose_name_plural = "用户表" #添加用户表到后台中去
def __str__(self):
return self.username
class Role(models.Model):
"""
角色表
"""
title = models.CharField(max_length=32)
permissions = models.ManyToManyField(verbose_name=\'具有的所有权限\',to=\'Permission\',blank=True) #blank=True的作用是关联的角色可以为空
class Meta:
verbose_name_plural = "角色表" #添加角色表到后台中去
def __str__(self):
return self.title
x
1
#创建表
2
3
from django.db import models
4
5
class Permission(models.Model):
6
"""
7
权限表
8
"""
9
title = models.CharField(verbose_name=\'标题\',max_length=32)
10
url = models.CharField(verbose_name="含正则URL",max_length=64)
11
is_menu = models.BooleanField(verbose_name="是否是菜单")
12
class Meta:
13
verbose_name_plural = "权限表" #添加表到后台中去
14
15
def __str__(self):
16
return self.title
17
18
class User(models.Model):
19
"""
20
用户表
21
"""
22
username = models.CharField(verbose_name=\'用户名\',max_length=32) #verbose_name将在后台页面上显示自定义的名字
23
password = models.CharField(verbose_name=\'密码\',max_length=64)
24
email = models.CharField(verbose_name=\'邮箱\',max_length=32)
25
roles = models.ManyToManyField(verbose_name=\'具有的所有角色\',to="Role",blank=True)
26
class Meta:
27
verbose_name_plural = "用户表" #添加用户表到后台中去
28
29
def __str__(self):
30
return self.username
31
32
class Role(models.Model):
33
"""
34
角色表
35
"""
36
title = models.CharField(max_length=32)
37
permissions = models.ManyToManyField(verbose_name=\'具有的所有权限\',to=\'Permission\',blank=True) #blank=True的作用是关联的角色可以为空
38
class Meta:
39
verbose_name_plural = "角色表" #添加角色表到后台中去
40
41
def __str__(self):
42
return self.title
43
44
45
46
47
48
49
第二步
根据django自己的admin来登陆
from django.conf.urls import url
from django.contrib import admin
from rbac import views
from app01 import views as app01_views
urlpatterns = [
url(r\'^admin/\', admin.site.urls),
]
xxxxxxxxxx
7
1
from django.conf.urls import url
2
from django.contrib import admin
3
from rbac import views
4
from app01 import views as app01_views
5
urlpatterns = [
6
url(r\'^admin/\', admin.site.urls),
7
]
在项目目录里创建登陆用户名和密码
#创建用户名和密码
python manage.py createsuperuser
xxxxxxxxxx
3
1
#创建用户名和密码
2
python manage.py createsuperuser
3
然后进行登陆输入你自己创建的用户名和密码
登陆进去,那么怎么显示你的表呢
#在admin.py里导入
from django.contrib import admin
from . import models
admin.site.register(models.Permission)
admin.site.register(models.User)
admin.site.register(models.Role)
xxxxxxxxxx
6
1
#在admin.py里导入
2
from django.contrib import admin
3
from . import models
4
admin.site.register(models.Permission)
5
admin.site.register(models.User)
6
admin.site.register(models.Role)
运行结果
可以看到默认是数据库的表名一一对应的,还可以更改名字
class Role(models.Model):
"""
角色表
"""
title = models.CharField(max_length=32)
permissions = models.ManyToManyField(verbose_name=\'具有的所有权限\',to=\'Permission\',blank=True)
class Meta:
verbose_name_plural = "角色表"
def __str__(self):
return self.title
class Meta: #添加 Meta
verbose_name_plural = "角色表" #更改名字
xxxxxxxxxx
14
1
class Role(models.Model):
2
"""
3
角色表
4
"""
5
title = models.CharField(max_length=32)
6
permissions = models.ManyToManyField(verbose_name=\'具有的所有权限\',to=\'Permission\',blank=True)
7
class Meta:
8
verbose_name_plural = "角色表"
9
10
def __str__(self):
11
return self.title
12
13
class Meta: #添加 Meta
14
verbose_name_plural = "角色表" #更改名字
输出结果:
第三步
用户登录程序
- 获取当前用户具有的所有权限(去重)
- 获取权限中的url,放置到session中
初始化权限信息,获取权限信息并放置到session中
import re
from django.shortcuts import render,redirect,HttpResponse
from rbac import models
from rbac.service.init_permission import init_permission #导入自己写的初始化的模块
def login(request):
if request.method == "GET":
return render(request,\'login.html\')
else:
user = request.POST.get(\'user\')
pwd = request.POST.get(\'pwd\')
user = models.User.objects.filter(username=user,password=pwd).first() #首先先查到用户输入的user字段存不存在找到用户输入的字段
print(request.POST)
if not user: #判断用户在不在
return render(request, \'login.html\') #如果不在则返回login页面
init_permission(user,request) #把user的对象和接收的用户信息传过去
return redirect(\'/index/\')
def index(request):
return HttpResponse(\'欢迎登录\')
def userinfo(request):
return HttpResponse(\'用户列表页面\')
def userinfo_add(request):
return HttpResponse(\'添加用户页面\')
def order(request):
return HttpResponse(\'订单列表页面\')
def order_add(request):
return HttpResponse(\'添加订单页面\')
x
1
import re
2
3
from django.shortcuts import render,redirect,HttpResponse
4
from rbac import models
5
from rbac.service.init_permission import init_permission #导入自己写的初始化的模块
6
def login(request):
7
if request.method == "GET":
8
return render(request,\'login.html\')
9
else:
10
user = request.POST.get(\'user\')
11
pwd = request.POST.get(\'pwd\')
12
user = models.User.objects.filter(username=user,password=pwd).first() #首先先查到用户输入的user字段存不存在找到用户输入的字段
13
print(request.POST)
14
if not user: #判断用户在不在
15
return render(request, \'login.html\') #如果不在则返回login页面
16
init_permission(user,request) #把user的对象和接收的用户信息传过去
17
return redirect(\'/index/\')
18
19
20
def index(request):
21
22
return HttpResponse(\'欢迎登录\')
23
24
25
def userinfo(request):
26
return HttpResponse(\'用户列表页面\')
27
28
29
def userinfo_add(request):
30
return HttpResponse(\'添加用户页面\')
31
32
def order(request):
33
return HttpResponse(\'订单列表页面\')
34
35
def order_add(request):
36
return HttpResponse(\'添加订单页面\')
def init_permission(user,request): #这里接受了视图函数传过来的user querset对象和request用户的信息
"""
初始化权限信息,获取权限信息并放置到session中。
:param user:
:param request:
:return:
"""
permission_list = user.roles.values(\'permissions__title\', \'permissions__url\', \'permissions__is_menu\').distinct() # 通过user的对象正向查询向下滑线查询拿到title,url,is_menu字段并进行去重
url_list = [] #定义一个空字典
for item in permission_list: #循环permission_list所有的值
url_list.append(item[\'permissions__url\']) #把url的字段的内容放入定义的空字典中
print(url_list)
request.session[\'permission_url_list\'] = url_list #通过这里通过了说明这个用户名是存在的把所有的url字段权限的信息加入到session中
x
1
def init_permission(user,request): #这里接受了视图函数传过来的user querset对象和request用户的信息
2
"""
3
初始化权限信息,获取权限信息并放置到session中。
4
:param user:
5
:param request:
6
:return:
7
"""
8
permission_list = user.roles.values(\'permissions__title\', \'permissions__url\', \'permissions__is_menu\').distinct() # 通过user的对象正向查询向下滑线查询拿到title,url,is_menu字段并进行去重
9
url_list = [] #定义一个空字典
10
for item in permission_list: #循环permission_list所有的值
11
url_list.append(item[\'permissions__url\']) #把url的字段的内容放入定义的空字典中
12
print(url_list)
13
request.session[\'permission_url_list\'] = url_list #通过这里通过了说明这个用户名是存在的把所有的url字段权限的信息加入到session中
14
第四步
在通过中间件来进行权限的管理
想要进行权限控制需要login和后台的admin路径对外开放,然后用户能够通过登陆来进行权限的验证,不然就会陷入死循环
白名单:
#自定制的
# ######################### rbac ############################
#白名单
VALID_URL = [
"/login/",
"/admin.*"
]
xxxxxxxxxx
7
1
#自定制的
2
# ######################### rbac ############################
3
#白名单
4
VALID_URL = [
5
"/login/",
6
"/admin.*"
7
]
import re
from django.shortcuts import redirect,HttpResponse
from django.conf import settings #settings是django特有的 在settings中都可以通过django.conf来调用,
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, \'process_request\'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, \'process_response\'):
response = self.process_response(request, response)
return response
class RbacMiddleware(MiddlewareMixin):
def process_request(self,request):
# 1. 获取当前请求的URL
# request.path_info
# 2. 获取Session中保存当前用户的权限
# request.session.get("permission_url_list\')
current_url = request.path_info #获取到用户输入的Url地址
# 当前请求不需要执行权限验证
for url in settings.VALID_URL: #拿到白名单 进行for循环验证因为白名单是一个列表的形式如果用户输入的url存在于白名单之中的
if re.match(url,current_url): #用循环取出的白名单与用户输入的url路径进行re正则判断,判断成功则有值,没有成功则没有值
return None #成功return None 则继续运行后面的中间件和视图函数
permission_list = request.session.get("permission_url_list") #通过request,get session中的值,如果没有则为空
if not permission_list: #进行判断
return redirect(\'/login/\') #没有的话则重定向login登陆页面中
#如果有的话则继续执行下面代码
flag = False
for db_url in permission_list: #有值则循环取值
regax = "^{0}$".format(db_url) #把循环的值通过.format按索引值穿参进行字符串拼接 注:如果不进行字符串的拼接加上^$的话,匹配的值只要一个正确后面的就不管了,比如addteacher/ addteacher/add/1这样的也能匹配成功,所以通过^$以..开头和以..结尾能够进行精确的匹配
if re.match(regax, current_url): #进行re正则匹配这样就能精确的匹配了,
flag = True #正则匹配成功的话flag=True
break #匹配成功了直接就退出循环了
if not flag: #用户的权限不匹配的话,则进行not false 就是true表示成功则往下执行
return HttpResponse(\'无权访问\') #直接返回无权访问
x
1
import re
2
3
from django.shortcuts import redirect,HttpResponse
4
from django.conf import settings #settings是django特有的 在settings中都可以通过django.conf来调用,
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
def process_request(self,request):
25
# 1. 获取当前请求的URL
26
# request.path_info
27
# 2. 获取Session中保存当前用户的权限
28
# request.session.get("permission_url_list\')
29
current_url = request.path_info #获取到用户输入的Url地址
30
31
# 当前请求不需要执行权限验证
32
for url in settings.VALID_URL: #拿到白名单 进行for循环验证因为白名单是一个列表的形式如果用户输入的url存在于白名单之中的
33
if re.match(url,current_url): #用循环取出的白名单与用户输入的url路径进行re正则判断,判断成功则有值,没有成功则没有值
34
return None #成功return None 则继续运行后面的中间件和视图函数
35
36
permission_list = request.session.get("permission_url_list") #通过request,get session中的值,如果没有则为空
37
if not permission_list: #进行判断
38
return redirect(\'/login/\') #没有的话则重定向login登陆页面中
39
#如果有的话则继续执行下面代码
40
flag = False
41
for db_url in permission_list: #有值则循环取值
42
regax = "^{0}$".format(db_url) #把循环的值通过.format按索引值穿参进行字符串拼接 注:如果不进行字符串的拼接加上^$的话,匹配的值只要一个正确后面的就不管了,比如addteacher/ addteacher/add/1这样的也能匹配成功,所以通过^$以..开头和以..结尾能够进行精确的匹配
43
if re.match(regax, current_url): #进行re正则匹配这样就能精确的匹配了,
44
flag = True #正则匹配成功的话flag=True
45
break #匹配成功了直接就退出循环了
46
47
if not flag: #用户的权限不匹配的话,则进行not false 就是true表示成功则往下执行
48
return HttpResponse(\'无权访问\') #直接返回无权访问
49
权限管理流程图