一、权限分配
需求:为用户分配角色,为角色分配权限,如下图效果:
1、视图代码:
from django.shortcuts import render from django.http import JsonResponse from rbac.models import User, Role, Permission def distribute_permissions(request): """ 分配权限 """ uid = request.GET.get('uid') user = User.objects.filter(id=uid) rid = request.GET.get('rid') # 保存为用户分配的角色 if request.method == 'POST' and request.POST.get('postType') == 'role': r_lst = request.POST.getlist("roles") user.first().roles.set(r_lst) # 保存为角色分配的权限 if request.method == 'POST' and request.POST.get('postType') == 'permission': p_lst = request.POST.getlist("permissions_id") Role.objects.filter(pk=rid).first().permissions.set(p_lst) user_list = User.objects.all() role_list = Role.objects.all() if uid: # 选中某一用户,则显示其对应角色 role_id_list= User.objects.get(pk=uid).roles.all().values_list("pk") role_id_list = [item[0] for item in role_id_list] if rid: # 点击某一角色,则显示其对应的权限 per_id_list = Role.objects.filter(pk=rid).values_list("permissions__pk").distinct() else: # 不点击角色,则显示选中用户对应角色拥有的权限 per_id_list = User.objects.get(pk=uid).roles.values_list("permissions__pk").distinct() per_id_list = [item[0] for item in per_id_list] return render(request, 'distribute_permission.html', locals()) # 显示权限表,ajax请求对应的视图函数 def permissions_tree(request): permissions = Permission.objects.values("pk", "title", "url", "menu__title", "menu__pk", "pid_id") return JsonResponse(list(permissions), safe=False)
注意:JsonResponse传入一个非字典类型的数据结构时,需要设置safe=False。
2、模板代码
1)显示用户表相关代码
<div class="am-panel-bd"> <ul class="user_ul"> {% for user in user_list %} <li class={% if user.id|safe == uid %}"active"{% endif %}> <a href="?uid={{ user.id }}">{{ user.name }}</a> </li> {% endfor %} </ul> </div>
2)显示角色表相关代码
<table class="am-table table-main mytable"> <thead> <tr class="am-primary"> <th>角色</th> <th>选择</th> </tr> </thead> <tbody> {% for role in role_list %} <tr class={% if role.id|safe == rid %}"am-danger"{% endif %}> {% load my_tags %} <td> <a href="?{% get_role_url request role.id %}">{{ role.title }}</a> </td> <td> {% if role.id in role_id_list %} <input type="checkbox" name="roles" value="{{ role.id }}" checked /> {% else %} <input type="checkbox" name="roles" value="{{ role.id }}" /> {% endif %} </td> </tr> {% endfor %} </tbody> </table>
3)显示权限表相关代码
<div class="am-panel-hd"> <span style="margin-left: 6px;">权限分配</span> {% if rid %} <button type="submit" class="am-btn am-fr"></i>保存</button> {% endif %} </div> <p class="per_tips">提示:点击角色后才能为其分配权限</p> <div class="am-panel-bd mypanel"> <table class="am-table table-main mytable"> <tbody id="tbd"> <!-- 通过文档加载时发送ajax请求获取用户权限,ajax代码如下 --> </tbody> </table> </div> {% block js %} <script> $.ajax({ url:"/rbac/permissions_tree/", type:"get", success:function (res) { console.log(res); $.each(res, function (i, permission) { // 渲染权限树形结构 console.log(i, permission); var menu_title = permission["menu__title"]; var menu_pk = permission["menu__pk"]; var url = permission["url"]; var parent_id = permission["pid_id"]; var pk = permission["pk"]; var title = permission["title"]; if (menu_title){ // 如果是菜单权限,即menu_id有值,pid_id为空 // 所属的一级菜单已经存在,则直接追加权限 if($("#menu_"+menu_pk).length){ var s = ` <tr id="per_${pk}"> <td class=""> <div class=""> <label> <input name="permissions_id" value="${pk}" type="checkbox"> <span>${title}</span> </label> </div> </td> </tr> `; $("#menu_"+menu_pk).parent().append(s); }else { // 所属的一级菜单不存在,即渲染菜单,又渲染权限 var s = ` <tr class="" id="menu_${menu_pk}"> <td>${menu_title}</td> </tr> <tr id="per_${pk}"> <td class=""> <div class=""> <label> <input name="permissions_id" value="${pk}" type="checkbox"> <span>${title}</span> </label> </div> </td> </tr> `; $("#tbd").append(s); } }else { // 如果不是菜单权限,即menu_id为空,pid_id有值 var s = ` <div class=""> <label> <input name="permissions_id" value="${pk}" type="checkbox"> <span>${title}</span> </label> </div> `; $("#per_"+parent_id+" td").append(s); } }); // 选中角色对应的权限 var per_id_list = {{ per_id_list }} $.each(per_id_list, function (i, j) { console.log($("[value='"+j+"']")[0]); $("#tbd [value='"+j+"']").prop("checked", true); }) } }) </script> {% endblock %}
3、思路分析
此需求难点是将权限表渲染在页面,有两种方案:在前端处理和在后端构建数据结构。
后端构建数据结构比较复杂,涉及到联动等。所以我们可以从前端入手,充分利用jquery的选择器,根据从数据库拿到的权限信息,用jquery技术渲染出来自己需要的结构。
二、将权限组件移植到CRM项目
(1) 先将rbac组件移植到新的项目中;
(2) 将settings中 INSTALLED_APPS 中加入"rbac";
(3) 将新项目的用户表与rbac下的User表一对一关联;
(4) 数据迁移;
(5) 在登录成功后引入rbac下的initial_session方法,做登录用户的权限信息存储(注意user对象);
(6) 在setting是中引入rbac下的权限校验中间件;
(7) 在项目的base模板中引入菜单样式,渲染显示;