javaWeb用戶權(quán)限控制簡(jiǎn)單實(shí)現(xiàn)過程
最近在做一個(gè)網(wǎng)站類型的項(xiàng)目,要對(duì)用戶的訪問模塊(權(quán)限)進(jìn)行控制,所以設(shè)計(jì)并實(shí)現(xiàn)了一套簡(jiǎn)單的權(quán)限控制功能。
1. 數(shù)據(jù)庫設(shè)計(jì)
用戶: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 '上一級(jí)id', `level` int(4) DEFAULT NULL COMMENT '級(jí)別', 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 '權(quán)限碼', PRIMARY KEY (`user_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of users -- ----------------------------
1. 后端實(shí)現(xiàn)
項(xiàng)目中用SSM+freemarker框架,把權(quán)限封裝成權(quán)限樹的數(shù)據(jù)結(jié)構(gòu),然后轉(zhuǎn)成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">關(guān)閉</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 的參數(shù)配置,深入使用請(qǐng)參考 API 文檔(setting 配置詳解)
var setting = {
view : {
//dblClickExpand : false,
showLine : true, //是否顯示節(jié)點(diǎn)間的連線
},
check: {
enable: true,
//nocheckInherit: false,
chkStyle: "checkbox",
chkboxType: { "Y": "ps", "N": "ps" },
//autoCheckTrigger: true
},
callback : {
onCheck: zTreeOnCheck,
}
};
//checkbox點(diǎn)擊的回調(diào)事件
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("賦權(quán)成功!");
setTimeout(function(){top.dialog.get("set-dialog").close().remove();} , 600);
}
},
error : function() {
layer.msg("系統(tǒng)錯(cuò)誤,請(qǐng)聯(lián)系管理員!");
}
});
}
//關(guān)閉
$("#cancel").click(function() {
top.dialog.get("set-dialog").close().remove();
});
</script>
</body>
</html>
展示效果如下:

2) controller控制層用springmvc
在控制層把數(shù)據(jù)轉(zhuǎn)成json格式,發(fā)到展示層。
/**
* @fun 獲取分店用戶權(quán)限
* @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)){ //酒店
//查詢酒店權(quán)限樹
hotelMap=this.rightMaskService.getUserRightMaskOnTree(substoreid,id,"complete");
}else if("simple".equals(versions)){ //客棧
//查詢客棧權(quán)限樹
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服務(wù)層把權(quán)限封裝成滿足ztree格式的樹數(shù)據(jù)結(jié)構(gòu)
/**
* @fun 獲取分店用戶權(quán)限
* @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 封裝一個(gè)一級(jí)樹
* @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 封裝一個(gè)二級(jí)樹
* @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 封裝一個(gè)三級(jí)樹
* @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 驗(yàn)證authCode中是否有l(wèi)ist中的權(quán)限碼
* @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層查詢數(shù)據(jù)庫獲得用戶權(quán)限
a.在數(shù)據(jù)層按權(quán)限級(jí)別從modules表中分別拿出不同級(jí)別的權(quán)限
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表中拿出某用戶的所有權(quán)限(權(quán)限碼)
select auth_code from users where user_code='pifeng'
c.保存權(quán)限時(shí)不同級(jí)別之間的權(quán)限碼用英式分號(hào)“;”隔開,同一級(jí)別之間的權(quán)限碼用英式逗號(hào)“,”隔開。例如: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)根據(jù)用戶的權(quán)限碼用freemarker標(biāo)簽控制頁面功能模塊是否顯示
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>
<!--自動(dòng)導(dǎo)入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">
<!-- 關(guān)聯(lián)到我們之前定義的工具類 -->
<bean class="com.leike.util.MenuFunction" />
</entry>
</map>
</property>
</bean>
b.寫個(gè)類繼承TemplateMethodModel類,實(shí)現(xiàn)freemarker自定義方法,用于實(shí)現(xiàn)控制頁面模塊是否顯示
登陸的時(shí)候把用戶權(quán)限碼存入session中,然后從session中取權(quán)限。下面是一個(gè)例子:
public class MenuFunction implements TemplateMethodModel{
@Override
public Object exec(List arg0) throws TemplateModelException {
int level = Integer.valueOf(arg0.get(0).toString()); //模塊等級(jí)
int modelId=Integer.valueOf(arg0.get(1).toString()); //模塊id
int count=0; //記錄session是否有此模塊的權(quán)限碼
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(); //權(quán)限碼
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標(biāo)簽,控制模塊的顯示隱藏
Menucall中的兩個(gè)參數(shù),第一個(gè)為模塊等級(jí),第二個(gè)為模塊的id
例如:
<#if menucall(1,122)> <li style="line-height: 250%"> <a href="#" id="booknew"><i class="glyphicon"></i>預(yù)訂</a> </li> </#if>
以上就是對(duì)用戶的訪問模塊(權(quán)限)進(jìn)行控制的大體實(shí)現(xiàn)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java入門概念個(gè)人理解之package與import淺析
- 詳解Java類庫的概念以及import的使用方法
- Java里的static import使用小結(jié)
- Java如何利用Mybatis進(jìn)行數(shù)據(jù)權(quán)限控制詳解
- Java編程訪問權(quán)限的控制代碼詳解
- java中自定義Spring Security權(quán)限控制管理示例(實(shí)戰(zhàn)篇)
- 淺析Java中的訪問控制權(quán)限
- java中使用Filter控制用戶登錄權(quán)限具體實(shí)例
- Java import導(dǎo)入及訪問控制權(quán)限修飾符原理解析
相關(guān)文章
Java解析xml文件遇到特殊符號(hào)異常的情況(處理方案)
這篇文章主要介紹了Java解析xml文件遇到特殊符號(hào)&會(huì)出現(xiàn)異常的解決方案,實(shí)現(xiàn)思路很簡(jiǎn)單通過在讀取xml文件使用SAX解析前讀取reader,具體實(shí)現(xiàn)方法及示例代碼跟隨小編一起看看吧2021-05-05
Java協(xié)程編程之Loom項(xiàng)目實(shí)戰(zhàn)記錄
這篇文章主要介紹了Java協(xié)程編程之Loom項(xiàng)目嘗鮮,如果用嘗鮮的角度去使用Loom項(xiàng)目,可以提前窺探JVM開發(fā)者們是如何基于協(xié)程這個(gè)重大特性進(jìn)行開發(fā)的,這對(duì)于提高學(xué)習(xí)JDK內(nèi)核代碼的興趣有不少幫助,需要的朋友可以參考下2021-08-08
微信企業(yè)號(hào)驗(yàn)證/發(fā)送/接收消息
這篇文章主要介紹了微信企業(yè)號(hào)驗(yàn)證/發(fā)送/接收消息的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
Springboot集成magic-api的詳細(xì)過程
這篇文章主要介紹了Springboot集成magic-api的相關(guān)知識(shí),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06

