基于EasyUI 快速搭建权限管理平台
前言:
一.用户角色权限设计思路:
<1>不同职责的人员,对于系统操作的权限应该是不同;
<2>可以对“组”进行权限分配;
<3>权限管理系统应该是可扩展的;
<4>满足业务系统中的功能权限
2. 角色和操作的权限设计(
不同的应用场合,你可能会想出不同的需求,提了一个新的需求以后,可能会发现原来的设计没方法实现了,于是还要添加一个新的表。这也是上面所提到的问题。 其实不必想得那么复杂,权限可以简单描述为:
某某主体 在 某某领域 有 某某权限
1,主体可以是用户,可以是角色,也可以是一个部门
2, 领域可以是一个模块,可以是一个页面,也可以是页面上的按钮
3, 权限可以是“可见”,可以是“只读”,也可以是“可用”(如按钮可以点击)
其实就是Who、What、How的问题, 谁对什么功能,动作有怎样的操作权限
下面来看看表结构是如何设计的,代码如下:
from django.db import models # Create your models here. class Permission(models.Model):
caption = models.CharField(max_length=32)
parent_id = models.ForeignKey('Permission', related_name='k', to_field='id', null=True, blank=True)
code = models.CharField(max_length=64, null=True,blank=True)
method = models.CharField(max_length=16, null=True,blank=True)
kwargs = models.CharField(max_length=128, null=True,blank=True)
is_menu = models.BooleanField(default=False) def __str__(self):
return self.caption class Role(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name class RoleToPermission(models.Model):
menu_id = models.ForeignKey(Permission, to_field='id')
role_id = models.ForeignKey(Role, to_field='id') def __str__(self):
return "%s-%s" %(self.menu_id.caption, self.role_id.name)
# 目标,根据角色列表获取权限 li
# 获取当前用户的所有标题权限
# RoleToPermission.objects.filter(role_id__in=li,menu_id__is_menu=True).\
# values('menu_id__caption','menu_id__parent_id','menu_id__parent_id','menu_id__code') # 获取当前用户的所有权限
# RoleToPermission.objects.filter(role_id__in=li).\
# values('menu_id__caption','menu_id__parent_id','menu_id__parent_id','menu_id__code') class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64) def __str__(self):
return self.username class UserInfoToRole(models.Model):
user_id = models.ForeignKey(UserInfo, to_field='id')
role_id = models.ForeignKey(Role, to_field='id')
def __str__(self):
return '%s-%s' %(self.user_id.username, self.role_id.name)
用户,角色, 权限表
权限表直接将权限分为具体的标题级别,url或者具体的某种操作方法
##权限表与角色表关系
先来看看权限表的表结构是如何构造的:
class Permission(models.Model):
##菜单的的权限,主要是为后台界面菜单部分单独拆分出来的字段,跟下面定义的code,method,kwargs等字段进行区分
caption = models.CharField(max_length=32)
##用于构造树形结构的权限表,可以自己关联自己
parent_id = models.ForeignKey('Permission', related_name='k', to_field='id', null=True, blank=True)
##具体的某个访问的url
code = models.CharField(max_length=64, null=True,blank=True)
##具体的请求方法
method = models.CharField(max_length=16, null=True,blank=True)
##请求方法所带的参数
kwargs = models.CharField(max_length=128, null=True,blank=True)
##是否是菜单栏
is_menu = models.BooleanField(default=False) def __str__(self):
return self.caption
从上边的表可以看出,我们将权限分类处理,这样可以更清晰准确的针对不同类型的权限进行划分,并且构造出了有关联关系的树形结构
接下来将权限表与角色表通过多对多关联,代码如下:
class Role(models.Model):
#定义角色名称
name = models.CharField(max_length=32)
def __str__(self):
return self.name class RoleToPermission(models.Model):
##定义角色和权限的对应关系
menu_id = models.ForeignKey(Permission, to_field='id')
role_id = models.ForeignKey(Role, to_field='id') def __str__(self):
return "%s-%s" %(self.menu_id.caption, self.role_id.name)
# 目标,根据角色列表获取权限 li
# 获取当前用户的所有标题权限
# RoleToPermission.objects.filter(role_id__in=li,menu_id__is_menu=True).\
# values('menu_id__caption','menu_id__parent_id','menu_id__parent_id','menu_id__code')
##用户与角色关系
用户表UserInfo 通过中间表UserInfoToRole 多对多关联 角色表Role,具体代码如下
class Role(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64) def __str__(self):
return self.username class UserInfoToRole(models.Model):
user_id = models.ForeignKey(UserInfo, to_field='id')
role_id = models.ForeignKey(Role, to_field='id')
def __str__(self):
return '%s-%s' %(self.user_id.username, self.role_id.name)
##登录过程,根据用户信息,关联查询获取用户相关角色,根据用户所属的角色关联查询用户对应的权限,具体实现代码如下:
def login(request):
if request.method == 'POST':
user = request.POST.get('user')
pwd = request.POST.get('pwd')
obj = models.UserInfo.objects.filter(username=user, password=pwd).first()
if obj:
# 当前用户信息保存至Session
request.session['user_info'] = {'id': obj.id, 'name': obj.username} # 当前用户角色列表保存至Session
result_list = models.UserInfoToRole.objects.filter(user_id_id=obj.id).values('role_id_id')
role_list = list(map(lambda x: x['role_id_id'], result_list))
request.session['role_list'] = role_list # 当前用户所有权限加入Session
from django.db.models import Count, Min, Max, Sum
permission_list = models.RoleToPermission.objects.filter(role_id__in=role_list).values(
'menu_id_id').annotate(c=Count('menu_id_id')).values('menu_id__caption',
'menu_id__parent_id',
'menu_id__code',
'menu_id__method',
'menu_id__kwargs',
'menu_id__id')
# 根据permission_id去重
permission_list = list(permission_list)
request.session['permission_list'] = permission_list menu_list = models.RoleToPermission.objects.filter(role_id__in=role_list,menu_id__is_menu=True).values(
'menu_id_id').annotate(c=Count('menu_id_id')).values('menu_id__caption',
'menu_id__parent_id',
'menu_id__code',
'menu_id__method',
'menu_id__kwargs',
'menu_id__id',)
# 根据permission_id去重
menu_list = list(menu_list)
request.session['menu_list'] = menu_list return redirect('/index/')
return render(request, 'login.html')
Login
#自定义render,从session中获取menu_list,代码如下:
def my_render(request, template_name, context=None, *args, **kwargs):
session_menu_list = request.session['menu_list']
menu_list = build_tree(session_menu_list)
print(request.path_info.split('/')[1])
if context:
context['menu_list'] = menu_list
else:
context = {'menu_list': menu_list}
return render(request, template_name, context, *args, **kwargs)
my_render
#定义装饰器validator,用来验证用户所请求的url是否已经过授权,代码如下:
def validate(func):
def inner(request,*args,**kwargs):
session_perm_l = list(map(lambda x : x['menu_id__code'] , request.session['permission_list']))
if request.path_info.split('/')[1] in session_perm_l:
ret = func(request,*args,**kwargs)
return ret
else:
return HttpResponse('unauhoted')
return inner
Validate
#通过递归方法构建权限树形结构,代码如下:
def build_node(menu_list, dic):
#
for menu in menu_list:
if menu['id'] == dic['menu_id__parent_id']:
temp = {'id': dic['menu_id__id'],'text': dic['menu_id__caption'], 'url': dic['menu_id__code'],'children': []}
menu['children'].append(temp)
break
else:
build_node(menu['children'], dic) def build_tree(session_menu_list):
# [ {menu_id__parent_id: None, 'menu_id__caption': '权限管理', 'menu_id__code': 'permission'},{},{} ]
menu_list = []
# menu_list = [{...}]
for dic in session_menu_list:
if dic['menu_id__parent_id'] == None:
temp = {'id': dic['menu_id__id'],'text': dic['menu_id__caption'], 'url': dic['menu_id__code'],'children': []}
menu_list.append(temp)
else:
# 当前
build_node(menu_list, dic)
return menu_list
build_tree
下面看下前端是如何实现的,前端使用EasyUI, 界面比较老旧,不过前端已经高度封装,有利于提高开发效率,首先我们先构建自己的母版,将基本的标题和样式,js文件,并展示出左侧菜单按钮
具体实现方法如下:
首先EasyUI以west,east,north,south,center 将前端分文左右上下中间的布局效果,具体实现代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Full Layout - jQuery EasyUI Demo</title>
<link rel="stylesheet" type="text/css" href="/static/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="/static/easyui/themes/icon.css">
<script type="text/javascript" src="/static/easyui/jquery.min.js"></script>
<script type="text/javascript" src="/static/easyui/jquery.easyui.min.js"></script>
<style>
.crm-menu{
display: block;
padding: 8px;
border-bottom: 1px dotted #dddddd;
}
.crm-menu:hover{
background-color: #E0ECFF;
}
</style>
{% block css %} {% endblock %}
</head>
<body class="easyui-layout">
<div data-options="region:'north',border:false" style="height:60px;background:#B3DFDA;padding:10px">
LOGO
</div>
<div data-options="region:'west',split:true,title:'West'" style="width:150px;">
<div id="aa" class="easyui-accordion" style="width:100%;"> {% for menu in menu_list %}
<div title="{{ menu.text }}" data-options="iconCls:'icon-ok'" style="overflow:auto;"> {% for child in menu.children %}
<a id="menu_{{ child.url }}" href='/{{ child.url }}/' class='crm-menu'>{{ child.text }}</a>
{% endfor %}
</div>
{% endfor %} </div> </div>
<div data-options="region:'south',border:false" style="height:50px;background:#A9FACD;padding:10px;">south region</div>
<div data-options="region:'center',title:'Center'">
{% block content %} {% endblock %}
</div> {% block js %} {% endblock %}
</body>
</html>
_layout.html
母版定义好后,我们可以基于母版定义具有树形结构的权限展示页面.
EasyUI可以通过两种方式实现此效果,通过“easyui_tree” 类实现树形菜单,也可以通过js生成前端展示页面,具体代码如下:
{% extends 'layout/_layout.html' %}
{% block content %}
<div style="float: left;width: 300px">
<ul id="pers_tree" ></ul>
<!-- <ul id="tt" class="easyui-tree" data-options="url:'/get_permission_tree/',method:'get',animate:true"></ul> -->
</div>
<div style="float: left;width: 600px">
<table id="dg"></table>
</div>
<div id="dlg" class="easyui-dialog" style="width:400px;height:200px;padding:10px 20px" closed="true" buttons="#dlg-buttons"> <!-#easyui订制模态对话框,默认关闭状态->
<form id="fm1">
<div class="input-group clearfix">
<div class="group-label" style="width: 80px;">
<span>省份:</span>
</div>
<div class="group-input" style="width: 300px;">
<input id="dlg_nid" style="width: 200px;display: none" name="nid"/>
<input id="dlg_province" style="width: 200px" class="easyui-textbox" type="text" name="caption" data-options="required:true,missingMessage:'省份不能为空'" />
</div>
</div>
</form>
</div>
<div id="dlg-buttons">
<span id="dlg_summary" style="color: red"></span>
<a href="#" class="easyui-linkbutton" iconCls="icon-ok" onclick="Save()">保存</a>
<a href="#" class="easyui-linkbutton" iconCls="icon-cancel" onclick="javascript:$('#dlg').dialog('close')">取消</a>
</div>
{% endblock %}
{% block js %}
<script>
$(function(){
InitTree();
});
function InitTree(){
$('#pers_tree').tree({
url: '/get_permission_tree/',
method: 'get',
animate: true,
onClick: function(node){
console.log(node.text,node.id);
InitTable(node.id);
InitPagination();
}
})
}
function InitTable(node_parent_id){
$('#dg').datagrid({
title: '听不下去了',
url: '/get_child_permission/',
method: 'get',
queryParams: {
node_parent_id: node_parent_id
},
columns: [[
{
field: 'ck',
checkbox: true
},
{
field: 'caption',
title: '标题',
width: 180,
align: 'center'
},
{
field: 'code',
title: 'URL',
width: 180,
align: 'center'
}
]],
toolbar: [
{
text: '添加',
iconCls: 'icon-add',
handler: AddRow
}, {
text: '删除',
iconCls: 'icon-remove',
handler: RemoveRow
}, {
text: '修改',
iconCls: 'icon-edit',
handler: EditRow
}
],
pagePosition: 'both',
pagination: true,
pageSize: 10,
pageNumber: 1,
pageList: [10, 20, 50]
})
}
function AddRow(){
// 显示对话框,由于希望添加则将方法设置为POST
$('#fm1').form('clear');
$('#dlg').dialog('open').dialog('setTitle','创建省份');
$('#dlg_summary').empty();
METHOD = 'post';
}
function RemoveRow(){
console.log('RemoveRow');
}
function EditRow(){
console.log('EditRow');
}
function InitPagination() {
var pager = $('#dg').datagrid('getPager');
$(pager).pagination({
beforePageText: '第',
afterPageText: '页 共{pages}页',
displayMsg: '当前显示{from}-{to}条记录 共{total}条数据'
})
}
</script>
{% endblock %}
EasyUI 已经高度封装了树形菜单的实现方法,我们只要了解具体的参数即可,详见http://www.jeasyui.com/demo/main/index.php
基于EasyUI 快速搭建权限管理平台的更多相关文章
- 基于EasyUI Treegrid的权限管理资源列表
1. 前言 最近在开发系统权限管理相关的功能,主要包含用户管理,资源管理,角色管理,组类别管理等小的模块.之前的Web开发中也用过jQueryEasyUI插件,感觉这款插件简单易用,上手很快.以前用到 ...
- EASYUI+MVC4通用权限管理平台
通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在平台开发完成后,特抽空总结一下平台知识,请各位在以后的时间里,关注博客的更新. 1.EASYUI+MVC4通用权限管理平台--前言 ...
- (转)EASYUI+MVC4通用权限管理平台
原文地址:http://www.cnblogs.com/hn731/archive/2013/07/15/3190947.html 通用权限案例平台在经过几年的实际项目使用,并取得了不错的用户好评.在 ...
- EASYUI+MVC4通用权限管理平台--前言
经过多年的管理信息系统的开发工作,吸取了工作中遇到的一些问题,经过自己的总结,形成了一套比较完整的管理信息系统的通用权限管理基础开发平台. 在软件的开发过程中我们首先需要解决的是UI问题,其次是浏览器 ...
- vue.js快速搭建图书管理平台
前 言 上一期简单讲解了vue的基本语法,这一次我们做一个小项目,搭建一个简单的图书管理平台,能够让我们更深刻的理解这门语言的妙用. 1.DEMO样式 首先我们需要搭建一个简单的demo样式 ...
- 基于fastadmin快速搭建后台管理
FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架:开发文档 下面对环境搭建简要概述,希望后来者能少走弯路: 1. 百度搜索最新版wampserver, 安装并启动 ...
- 基于 Jenkins 快速搭建持续集成环境--转
源地址:http://www.ibm.com/developerworks/cn/java/j-lo-jenkins/ 持续集成是一种软件开发实践,对于提高软件开发效率并保障软件开发质量提供了理论基础 ...
- Docker: 快速搭建LNMP网站平台
快速搭建LNMP网站平台 步骤: 1.自定义网络(这里建立一个自定义网络,名字叫 lnmp, 让LNMP网站的服务,都加入这个自定义网络)docker network create lnmp2.创建M ...
- Jenkins配置基于角色的项目权限管理--转
本文将介绍如何配置jenkins,使其可以支持基于角色的项目权限管理. 由于jenkins默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,本文将使用Role Str ...
随机推荐
- MFC存储图片到SQL Server数据库
第一步:建立数据库表,比如:id char,pic image. 第二步:建立MFC单文档应用程序,再添加类CMyRecordset,基类选择CRecordset,导入数据库的刚建立的表. 第三步:在 ...
- Spring中Adivisor和Aspect的差别(自我理解)
在AOP中有几个概念: - 方/切 面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象.事务管理是J2EE应用中一个非常好的横切关注点样例. 方面用Spring的Advisor ...
- JBPM4.4_工作流基础_准备jBPM4.4环境
1. 工作流基础 1.1. 工作流相关概念 工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档.信息或任 ...
- 自学Ajax
使用Ajax快捷函数 说明 出于简化AJAX开发工作的流程,jQuery提供了若干了快捷函数. 实例 1.显示 test.php 返回值(HTML 或 XML,取决于返回值). $.get(" ...
- codevs 5964 [SDOI2017]序列计数
[题解] 官方题解就两句话. 写了三个版本的不同分值代码.看代码吧. 前导1 //f[i][j][1/0]表示长为i,sum mod p=j,是否已经选了质数的方案数 #include<cst ...
- vue模糊查询
模糊查询匹配结果 <!-- 搜索框 --> <div class="search-wrapper"> <input type="text&q ...
- MongoDB插入多条数据
刚开始学mongodb,只知道几个命令,insert插入也只能一条一条插入,而在实际情况下数据一般都非常多,刚开始想直接上传json文件,网上搜了n多方法发现这种方法不好弄,然后就想着要么一下子把多条 ...
- 170331、58到家MQ如何快速实现流量削峰填谷
问:为什么会有本文? 答:上一篇文章<到底什么时候该使用MQ?>引起了广泛的讨论,有朋友回复说,MQ的还有一个典型应用场景是缓冲流量,削峰填谷,本文将简单介绍下,MQ要实现什么细节,才能缓 ...
- 170308、oracle查看被锁的表和解锁
--以下几个为相关表SELECT * FROM v$lock;SELECT * FROM v$sqlarea;SELECT * FROM v$session;SELECT * FROM v$proce ...
- [ Office 365 开发系列 ] 身份认证
前言 本文完全原创,转载请说明出处,希望对大家有用. 通常我们在开发一个应用时,需要考虑用户身份认证及授权,Office 365使用AAD(Azure Active Directory)作为其认证机构 ...