最近在做一个网站类型的项目,要对用户的访问模块(权限)进行控制,所以设计并实现了一套简单的权限控制功能。
1. 数据库设计
用户:users
模块:modules
SQL代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/* Target Server Type : MYSQL Target Server Version : 50628 File Encoding : 65001 Date : 2016-08-26 10:35:28 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `modules` -- ---------------------------- DROP TABLE IF EXISTS `modules`; CREATE TABLE `modules` ( `id` int (10) NOT NULL AUTO_INCREMENT, `module` varchar (30) DEFAULT NULL COMMENT '模块' , `pid` int (10) DEFAULT NULL COMMENT '上一级id' , ` level ` int (4) DEFAULT NULL COMMENT '级别' , PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of modules -- ---------------------------- -- ---------------------------- -- Table structure for `users` -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `user_code` varchar (10) NOT NULL COMMENT '用户代码' , `user_name` varchar (40) DEFAULT NULL COMMENT '用户名' , `user_password` varchar (100) DEFAULT NULL COMMENT '密码' , `qq` varchar (15) DEFAULT NULL COMMENT 'qq' , `msn` varchar (50) DEFAULT NULL COMMENT 'msn' , `demo` varchar (100) DEFAULT NULL COMMENT '备注' , `auth_code` text COMMENT '权限码' , PRIMARY KEY (`user_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of users -- ---------------------------- |
1. 后端实现
项目中用SSM+freemarker框架,把权限封装成权限树的数据结构,然后转成json格式。
1) 展示层采用ztree树(setUserauthOnTree.html)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
<!DOCTYPE html> < html > < head > <#include "common/res.html" /> < script src = "${base.ctx}/js/layer-v2.1/laypage/laypage.js" ></ script > < link href = "${base.ctx}/js/layer-v2.1/laypage/skin/laypage.css" rel = "stylesheet" type = "text/css" /> < script src = "${base.ctx}/js/layer-v2.1/layer/layer.js" ></ script > <!-- 引入树形菜单样式 --> < link href = "${base.ctx}/component/ztree/css/zTreeStyle/zTreeStyle.css" rel = "stylesheet" type = "text/css" /> < script type = "text/javascript" src = "${base.ctx}/component/ztree/js/jquery.ztree.core-3.5.js" ></ script > < script type = "text/javascript" src = "${base.ctx}/component/ztree/js/jquery.ztree.excheck-3.5.js" ></ script > < style type = "text/css" > .blue-madison { border: 1px solid #7ca7cc; border-top: 0; } .caption { background-color: #578ebe; border-bottom: 0; padding: 0 10px; margin-bottom: 0; color: #fff; } </ style > </ head > < body > < div class = "portlet-body" style = "overflow-y:auto; width:400px; height:550px;" > < div id = "ztree" > < ul id = "treeDemo" class = "ztree" ></ ul > </ div > </ div > < div class = "form-actions" > < div class = "row" > < div class = "col-sm-12" align = "center" style = "margin-top: 5px" > < button type = 'button' class = "btn btn-primary" onclick = "editModle()" >确定</ button > < button type = "button" class = "btn btn-primary" id = "cancel" >关闭</ button > </ div > </ div > </ div > < script > $("document").ready(function() { $.ajax({ type : "post", url : "${base.ctx}/Setup/getUserRightMaskById", data:{"id":"${userId}"}, dataType : "json", success : function(result) { zTreeObj = $.fn.zTree.init($("#treeDemo"), setting,result.datas.data); zTreeObj.expandAll(true); }, error : function() { } }); }); //加载树 var zTreeObj; // zTree 的参数配置,深入使用请参考 API 文档(setting 配置详解) var setting = { view : { //dblClickExpand : false, showLine : true, //是否显示节点间的连线 }, check: { enable: true, //nocheckInherit: false, chkStyle: "checkbox", chkboxType: { "Y": "ps", "N": "ps" }, //autoCheckTrigger: true }, callback : { onCheck: zTreeOnCheck, } }; //checkbox点击的回调事件 function zTreeOnCheck(event, treeId, treeNode) { /* var zTree = $.fn.zTree.getZTreeObj("treeDemo"); var changedNodes = zTree.getChangeCheckedNodes(); for ( var i=0 ; i < changedNodes.length ; i++ ){ var treeNode = changedNodes [i]; } */ }; function editModle(){ var rootId = null ; var midId = null ; var minId = null ; var treeObj = $.fn.zTree.getZTreeObj("treeDemo"); var nodes = treeObj .getCheckedNodes(); for(var i = 0 ;i<nodes.length;i++){ if(nodes[i].level==0){ rootId =rootId+","+nodes[i].id; } if(nodes[i].level==1){ midId =midId+","+nodes[i].id; } if(nodes[i].level==2){ minId =minId+","+nodes[i].id; } } if(rootId!=null){ rootId =rootId.substring(5,rootId.length); } if(midId!=null){ midId =midId.substring(5,midId.length); } if(minId!=null){ minId =minId.substring(5,minId.length); } $.ajax({ type : "post", url : "${base.ctx}/Setup/updateUserRightMaskByAjax", dataType : "json", data:{"rootId":rootId,"midId":midId,"minId":minId,"userId":"${userId}"}, success : function(result) { if(result=="1"){ layer.msg("赋权成功!"); setTimeout(function(){top.dialog.get("set-dialog").close().remove();} , 600); } }, error : function() { layer.msg("系统错误,请联系管理员!"); } }); } //关闭 $("#cancel").click(function() { top.dialog.get("set-dialog").close().remove(); }); </script> </ body > </ html > |
展示效果如下:
2) controller控制层用springmvc
在控制层把数据转成json格式,发到展示层。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/** * @fun 获取分店用户权限 * @author 皮锋 * @date 2016/8/25 * @param session * @param id * @param substoreid * @return */ @RequestMapping ( "getUserRightMaskById" ) @ResponseBody public Object getUserRightMaskById(HttpSession session,String id,String substoreid){ substoreid=StringUtils.isEmpty(substoreid)?String.valueOf(session.getAttribute( "substoreid" )):substoreid; //判断是酒店还是客栈 List<Map<String, Object>> versionsList= this .setupService.getHotelHotelVersions(substoreid); Object versions=versionsList.get( 0 ).get( "versions" ); Map<String, Object> hotelMap= new HashMap<String, Object>(); if (( null !=versionsList)&&(versionsList.size()!= 0 )){ //list不为空 if ( "complete" .equals(versions)){ //酒店 //查询酒店权限树 hotelMap= this .rightMaskService.getUserRightMaskOnTree(substoreid,id, "complete" ); } else if ( "simple" .equals(versions)){ //客栈 //查询客栈权限树 hotelMap= this .rightMaskService.getUserRightMaskOnTree(substoreid,id, "simple" ); } } Map<String, Object> resultMap = new HashMap<String, Object>(); resultMap.put( "datas" , hotelMap); return JSONObject.toJSONString(resultMap, SerializerFeature.WriteMapNullValue); } |
3)service服务层把权限封装成满足ztree格式的树数据结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
/** * @fun 获取分店用户权限 * @author 皮锋 * @date 2016/8/25 * @param substoreid * @param id * @param versions * @return Map<String, Object> */ @Override public Map<String, Object> getUserRightMaskOnTree(String substoreid, String id, String versions) { Map<String, Object> userRightMask= this .iRightMaskDao.getUserRightMaskBySubAndId(substoreid,id); List<Map<String, Object>> listOne = new ArrayList<Map<String,Object>>(); List<Map<String, Object>> listTwo = new ArrayList<Map<String,Object>>(); //List<Map<String, Object>> listThree = new ArrayList<Map<String,Object>>(); List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(); if (versions.equals( "complete" )){ //酒店 listOne = this .iRightMaskDao.getRightMaskOnHotelOne(); listTwo = this .iRightMaskDao.getRightMaskOnHotelTwo(); //listThree = this.iRightMaskDao.getRightMaskOnHotelThree(); packagingToTwoTree(resultList,listOne,listTwo,userRightMask); } else if (versions.equals( "simple" )){ //客栈 listOne = this .iRightMaskDao.getRightMaskOnTavernOne(); listTwo = this .iRightMaskDao.getRightMaskOnTavernTwo(); //listThree = this.iRightMaskDao.getRightMaskOnTavernThree(); packagingToTwoTree(resultList,listOne,listTwo,userRightMask); } Map<String, Object> map = new HashMap<String, Object>(); map.put( "data" , resultList); return map; } /** * @function 封装一个一级树 * @author 皮锋 * @date 2016/8/26 * @param resultList * @param listOne * @param authCode * @return void */ private void packagingToOneTree(List<Map<String, Object>> resultList, List<Map<String, Object>> listOne, Map<String, Object> authCode) { for ( int i = 0 ; i < listOne.size(); i++) { Map<String, Object> rootMap = new HashMap<String, Object>(); rootMap.put( "id" , listOne.get(i).get( "id" )); rootMap.put( "name" , listOne.get(i).get( "module" )); if (validateRightMask(listOne, authCode, i) != - 1 ) { rootMap.put( "checked" , true ); } else { rootMap.put( "checked" , false ); } resultList.add(rootMap); } } /** * @function 封装一个二级树 * @author 皮锋 * @date 2016/8/26 * @param resultList * @param listOne * @param listTwo * @param authCode * @return void */ private void packagingToTwoTree(List<Map<String, Object>> resultList, List<Map<String, Object>> listOne, List<Map<String, Object>> listTwo, Map<String, Object> authCode) { for ( int i = 0 ; i < listOne.size(); i++) { List<Map<String, Object>> midList = new ArrayList<Map<String, Object>>(); for ( int j = 0 ; j < listTwo.size(); j++) { if (listTwo.get(j).get( "pid" ).toString() .equals(listOne.get(i).get( "id" ).toString())) { List<Map<String, Object>> minlist = new ArrayList<Map<String, Object>>(); Map<String, Object> midMap = new HashMap<String, Object>(); midMap.put( "id" , listTwo.get(j).get( "id" )); midMap.put( "name" , listTwo.get(j).get( "module" )); midMap.put( "children" , minlist); if (validateRightMask(listTwo, authCode, j) != - 1 ) { midMap.put( "checked" , true ); } else { midMap.put( "checked" , false ); } midList.add(midMap); } } Map<String, Object> rootMap = new HashMap<String, Object>(); rootMap.put( "id" , listOne.get(i).get( "id" )); rootMap.put( "name" , listOne.get(i).get( "module" )); rootMap.put( "children" , midList); if (validateRightMask(listOne, authCode, i) != - 1 ) { rootMap.put( "checked" , true ); } else { rootMap.put( "checked" , false ); } resultList.add(rootMap); } } /** * @function 封装一个三级树 * @author 皮锋 * @date 2016/8/26 * @param resultList * @param listOne * @param listTwo * @param listThree * @param authCode * @return void */ private void packagingToThreeTree(List<Map<String, Object>> resultList, List<Map<String, Object>> listOne, List<Map<String, Object>> listTwo, List<Map<String, Object>> listThree, Map<String, Object> authCode) { for ( int i = 0 ; i < listOne.size(); i++) { List<Map<String, Object>> midList = new ArrayList<Map<String, Object>>(); for ( int j = 0 ; j < listTwo.size(); j++) { if (listTwo.get(j).get( "pid" ).toString() .equals(listOne.get(i).get( "id" ).toString())) { List<Map<String, Object>> minlist = new ArrayList<Map<String, Object>>(); for ( int k = 0 ; k < listThree.size(); k++) { Map<String, Object> minMap = new HashMap<String, Object>(); if (listThree.get(k).get( "pid" ).toString() .equals(listTwo.get(j).get( "id" ).toString())) { minMap.put( "id" , listThree.get(k).get( "id" )); minMap.put( "name" , listThree.get(k).get( "module" )); if (validateRightMask(listThree, authCode, k) != - 1 ) { minMap.put( "checked" , true ); } else { minMap.put( "checked" , false ); } minlist.add(minMap); } } Map<String, Object> midMap = new HashMap<String, Object>(); midMap.put( "id" , listTwo.get(j).get( "id" )); midMap.put( "name" , listTwo.get(j).get( "module" )); midMap.put( "children" , minlist); if (validateRightMask(listTwo, authCode, j) != - 1 ) { midMap.put( "checked" , true ); } else { midMap.put( "checked" , false ); } midList.add(midMap); } } Map<String, Object> rootMap = new HashMap<String, Object>(); rootMap.put( "id" , listOne.get(i).get( "id" )); rootMap.put( "name" , listOne.get(i).get( "module" )); rootMap.put( "children" , midList); if (validateRightMask(listOne, authCode, i) != - 1 ) { rootMap.put( "checked" , true ); } else { rootMap.put( "checked" , false ); } resultList.add(rootMap); } } /** * @function 验证authCode中是否有list中的权限码 * @author 皮锋 * @date 2016/8/26 * @param list * @param authCode * @param i * @return int */ private int validateRightMask(List<Map<String, Object>> list, Map<String, Object> authCode, int i) { String rightMask = authCode.get( "auth_code" ) != null ? authCode.get( "auth_code" ).toString() : "" ; if (!StringUtils.isEmpty(rightMask)) { rightMask = rightMask.replace( ";" , "," ); String[] arry = rightMask.split( "," ); for ( int j = 0 ; j < arry.length; j++) { String arryRightMask = arry[j]; String listRightMask = list.get(i).get( "id" ).toString(); if (arryRightMask.equals(listRightMask)) { return 1 ; } } } else { return - 1 ; } return - 1 ; } |
4) dao层查询数据库获得用户权限
a.在数据层按权限级别从modules表中分别拿出不同级别的权限
1
2
3
|
select id,module,pid, level from modules where level = '0' select id,module,pid, level from modules where level = '1' select id,module,pid, level from modules where level = '2' |
b.在users表中拿出某用户的所有权限(权限码)
select auth_code from users where user_code='pifeng'
c.保存权限时不同级别之间的权限码用英式分号“;”隔开,同一级别之间的权限码用英式逗号“,”隔开。例如:1,2,3,4,5,6,7,8,9,10,11,12;13,14,15,16,17,18,19,20,21,22,23,24,25,26,36,37,27,28,29,30,31,32,33,34,35,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,62,63,64,133,65,66,67,68,69,70,71,72,73,74,75,126,127,128,129,130,131,76,77,78,79,80,81,82,83,84,85,86,87,88,99,124,134,135,136,140,141,89,90,91,92,93,94,95,96,97,98,137,138,139,100,101,102,103,106,107,132,108,109,110,111,112,113,114,115,116,125,117,118,119,120,121,122
5)根据用户的权限码用freemarker标签控制页面功能模块是否显示
a.freemarker在xml文件中的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
<bean id= "freemarkerConfig" class = "org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer" > <!--模板加载路径--> <property name= "templateLoaderPath" > <value>/WEB-INF/ftl/</value> </property> <property name= "freemarkerVariables" > <map> <entry key= "xml_escape" value-ref= "fmXmlEscape" /> </map> </property> <property name= "freemarkerSettings" > <props> <prop key= "tag_syntax" >auto_detect</prop> <prop key= "template_update_delay" > 0 </prop> <prop key= "default_encoding" >UTF- 8 </prop> <prop key= "output_encoding" >UTF- 8 </prop> <prop key= "locale" >zh_CN</prop> <prop key= "date_format" >yyyy-MM-dd</prop> <prop key= "time_format" >HH:mm:ss</prop> <prop key= "number_format" > 0 .######</prop> <prop key= "datetime_format" >yyyy-MM-dd HH:mm:ss</prop> <!--空值处理--> <prop key= "classic_compatible" > true </prop> <!--自动导入ftl模板,并以“base”别名作为命名空间--> <prop key= "auto_import" >inc/spring.ftl as base</prop> </props> </property> </bean> <bean id= "fmXmlEscape" class = "freemarker.template.utility.XmlEscape" /> <bean id= "freeMarkerViewResolver" class = "org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver" > <property name= "suffix" value= ".html" /> <property name= "cache" value= "false" /> <property name= "viewClass" value= "org.springframework.web.servlet.view.freemarker.FreeMarkerView" /> <property name= "contentType" value= "text/html;charset=UTF-8" ></property> <!--fixed Exception:Cannot expose session attribute 'substoreid' because of an existing model --> <property name= "allowSessionOverride" value= "true" /> <property name= "exposeRequestAttributes" value= "true" /> <property name= "exposeSessionAttributes" value= "true" /> <property name= "exposeSpringMacroHelpers" value= "true" /> <!-- 此变量值为pageContext.request, 页面使用方法:request.contextPath --> <property name= "requestContextAttribute" value= "request" /> <property name= "attributesMap" > <map> <!-- 定义Freemarker方法的名称 --> <entry key= "menucall" > <!-- 关联到我们之前定义的工具类 --> <bean class = "com.leike.util.MenuFunction" /> </entry> </map> </property> </bean> |
b.写个类继承TemplateMethodModel类,实现freemarker自定义方法,用于实现控制页面模块是否显示
登陆的时候把用户权限码存入session中,然后从session中取权限。下面是一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public class MenuFunction implements TemplateMethodModel{ @Override public Object exec(List arg0) throws TemplateModelException { int level = Integer.valueOf(arg0.get( 0 ).toString()); //模块等级 int modelId=Integer.valueOf(arg0.get( 1 ).toString()); //模块id int count= 0 ; //记录session是否有此模块的权限码 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpSession session=request.getSession(); Object o = session.getAttribute( "info" ); if (o== null ) return false ; Info info = (Info) o; String authCode=info.getUser().getAuthCode(); //权限码 if (authCode.contains( ";" )){ String[] masks=authCode.split( ";" ); String[] m=masks[level].split( "," ); for ( int i = 0 ; i < m.length; i++) { if (modelId==Integer.parseInt(m[i])){ ++count; } else { count+= 0 ; } } } if (count== 0 ){ return false ; } else { return true ; } } } |
c.在页面使用freemarker标签,控制模块的显示隐藏
Menucall中的两个参数,第一个为模块等级,第二个为模块的id
例如:
1
2
3
4
5
|
<# if menucall( 1 , 122 )> <li style= "line-height: 250%" > <a href= "#" id= "booknew" ><i class = "glyphicon" ></i>预订</a> </li> </# if > |
以上就是对用户的访问模块(权限)进行控制的大体实现。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。