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>

 

 

 

 

以上就是對用戶的訪問模塊(權限)進行控制的大體實現。

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章