Recently, I am working on a website-type project that requires controlling the user's access module (permissions), so a simple set of permission control functions is designed and implemented.
1. Database design
User: users
Modules: modules
SQL Code:
/*Target Server Type : MYSQLTarget Server Version : 50628File Encoding : 65001Date: 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. Back-end implementation <br />The SSM+freemarker framework is used in the project to encapsulate permissions into the data structure of the permission tree, and then convert it into the json format.
1) The display layer adopts ztree tree (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><!-- Introducing tree menu style--><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 style="overflow-y:auto; width:400px; height:550px;"> <div id="ztree" > <ul id="treeDemo"></ul> </div> </div> <div> <div> <div align="center" style="margin-top: 5px"> <button type='button' onclick="editModle()">OK</button> <button type="button" id="cancel">Close</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() { } }); }); //Load the tree var zTreeObj; // For in-depth use, please refer to the API documentation (detailed explanation of setting configuration) var setting = { view : { //dblClickExpand : false, showLine : true, //Does the connection between nodes be displayed}, check: { enable: true, //nocheckInherit: false, chkStyle: "checkbox", chkboxType: { "Y": "ps", "N": "ps" }, //autoCheckTrigger: true }, callback : { onCheck: zTreeOnCheck, } }; //checkbox clicked callback event 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("Empowered successfully! "); setTimeout(function(){top.dialog.get("set-dialog").close().remove();} , 600); } }, error : function() { layer.msg("System error, please contact the administrator!"); } }); } //Close $("#cancel").click(function() { top.dialog.get("set-dialog").close().remove(); }); </script></body></html> The display effect is as follows:
2) Controller control layer uses springmvc
In the control layer, convert the data into json format and send it to the display layer.
/** * @fun Get branch user permissions* @author Pi Feng* @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; //Judge whether it is a hotel or an inn List<Map<String, Object>> versionsList=this.setupService.getHotelVersions(substoreid); Object versions=versionsList.get(0).get("versions"); Map<String, Object> hotelMap=new HashMap<String, Object>(); if((null!=versionsList)&&(versionsList.size()!=0)){ //list is not empty if("complete".equals(versions)){ //Hotel//Query hotel permission tree hotelMap=this.rightMaskService.getUserRightMaskOnTree(substoreid,id,"complete"); }else if("simple".equals(versions)){ //Inn//Query inn permission tree 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) The service service layer encapsulates permissions into a tree data structure that satisfies the ztree format
/** * @fun Get branch user permissions* @author Pi Feng* @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")){ //Hotel listOne = this.iRightMaskDao.getRightMaskOnHotelOne(); listTwo = this.iRightMaskDao.getRightMaskOnHotelTwo(); //listThree = this.iRightMaskDao.getRightMaskOnHotelThree(); packagingToTwoTree(resultList,listOne,listTwo,userRightMask); }else if(versions.equals("simple")){ //Inn 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 Encapsulate a first-level tree* @author Pi Feng* @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 Encapsulate a secondary tree* @author Pi Feng* @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 Encapsulate a third-level tree* @author Pi Feng* @date 2016/8/26 * @param resultList * @param listOne * @param listTwo * @param listTwo * @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 Verify whether there is permission code in authCode in the list* @author Pi Feng* @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[] array = rightMask.split(","); for (int j = 0; j < arry.length; j++) { String arrayRightMask = arry[j]; String listRightMask = list.get(i).get("id").toString(); if (arryRightMask.equals(listRightMask)) { return 1; } } } else { return -1; } return -1; } 4) Query the database to obtain user permissions
a. Take out different levels of permissions from the modules table according to the permission level in the data layer.
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. Take out all permissions of a user (permission code) in the users table
select auth_code from users where user_code='pifeng'
c. When saving permissions, the permission codes between different levels are separated by the British semicolon ";", and the permission codes between the same level are separated by the British comma ",". For example: 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,1 26,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) Use the freemarker tag to control whether the page function module is displayed according to the user's permission code
a. Freemarker configuration in xml file
<bean id="freemarkerConfig" > <!--Template Loading Path--> <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> <!--Null value processing--> <prop key="classic_compatible">true</prop> <!--Automatically import the ftl template and use the "base" alias as the namespace--> <prop key="auto_import">inc/spring.ftl as base</prop> </props> </property> </bean> <bean id="fmXmlEscape"/> <bean id="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"/> <!-- This variable value is pageContext.request, page usage method: request.contextPath --> <property name="requestContextAttribute" value="request"/> <property name="attributesMap"> <map> <!-- Define the name of the Freemarker method --> <entry key="menucall"> <!-- Associate to the tool class we defined earlier--> <bean /> </entry> </map> </property> </bean>
b. Write a class to inherit the TemplateMethodModel class and implement the freemarker custom method to control whether the page module displays login and store the user permission code into the session, and then obtain permission from the session. Here is an example:
public class MenuFunction implements TemplateMethodModel{ @Override public Object exec(List arg0) throws TemplateModelException { int level = Integer.valueOf(arg0.get(0).toString()); //Module level int modelId=Integer.valueOf(arg0.get(1).toString()); //Module id int count=0; //Record session whether there is permission code for this module 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(); //Permission code 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. Use freemarker tag on the page, and control the display of the module is hidden
Two parameters in Menucall, the first is the module level and the second is the module id
For example:
<#if menucall(1,122)> <li style="line-height: 250%"> <a href="#" id="booknew"><i></i>booking</a> </li></#if>
The above is the general implementation of controlling the user's access module (permissions).
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.