javaWeb用户权限控制简单实现过程
最近在做一个网站类型的项目,要对用户的访问模块(权限)进行控制,所以设计并实现了一套简单的权限控制功能。
1. 数据库设计
用户:users
模块:modules
sql代码:
/* 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)
<!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格式,发到展示层。
/** * @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格式的树数据结构
/** * @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表中分别拿出不同级别的权限
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文件中的配置
<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中取权限。下面是一个例子:
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
例如:
<#if menucall(1,122)> <li style="line-height: 250%"> <a href="#" id="booknew"><i class="glyphicon"></i>预订</a> </li> </#if>
以上就是对用户的访问模块(权限)进行控制的大体实现。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: php使用GD2绘制几何图形示例
下一篇: JDBC连接数据库的方法汇总