最近在做一个网站类型的项目,要对用户的访问模块(权限)进行控制,所以设计并实现了一套简单的权限控制功能。
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;
-
-
-
-
- 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;
-
-
-
-
-
-
-
-
- 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;
-
-
-
-
1. 后端实现
项目中用SSM+freemarker框架,把权限封装成权限树的数据结构,然后转成json格式。
1) 展示层采用ztree树(setUserauthOnTree.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格式,发到展示层。
-
-
-
-
-
-
-
-
-
- @RequestMapping("getUserRightMaskById")
- @ResponseBody
- public Object getUserRightMaskById(HttpSession session,String id,String substoreid){
- substoreid=StringUtils.isEmpty(substoreid)?String.valueOf(session.getAttribute("substoreid")):substoreid;
-
- List
- Object versions=versionsList.get(0).get("versions");
- Map hotelMap=new HashMap();
- if((null!=versionsList)&&(versionsList.size()!=0)){
- if("complete".equals(versions)){
-
- hotelMap=this.rightMaskService.getUserRightMaskOnTree(substoreid,id,"complete");
- }else if("simple".equals(versions)){
-
- hotelMap=this.rightMaskService.getUserRightMaskOnTree(substoreid,id,"simple");
- }
- }
- Map resultMap = new HashMap();
- resultMap.put("datas", hotelMap);
-
- return JSONObject.toJSONString(resultMap, SerializerFeature.WriteMapNullValue);
- }
3)service服务层把权限封装成满足ztree格式的树数据结构
-
-
-
-
-
-
-
-
-
- @Override
- public Map getUserRightMaskOnTree(String substoreid, String id, String versions) {
- Map userRightMask=this.iRightMaskDao.getUserRightMaskBySubAndId(substoreid,id);
- List
- List> listTwo = new ArrayList>();
-
- List> resultList = new ArrayList>();
- if(versions.equals("complete")){
- listOne = this.iRightMaskDao.getRightMaskOnHotelOne();
- listTwo = this.iRightMaskDao.getRightMaskOnHotelTwo();
-
- packagingToTwoTree(resultList,listOne,listTwo,userRightMask);
- }else if(versions.equals("simple")){
- listOne = this.iRightMaskDao.getRightMaskOnTavernOne();
- listTwo = this.iRightMaskDao.getRightMaskOnTavernTwo();
-
- packagingToTwoTree(resultList,listOne,listTwo,userRightMask);
- }
- Map map = new HashMap();
- map.put("data", resultList);
- return map;
- }
-
-
-
-
-
-
-
-
-
- private void packagingToOneTree(List> resultList,
- List> listOne, Map authCode) {
- for (int i = 0; i < listOne.size(); i++) {
- Map rootMap = new HashMap();
- 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);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
- private void packagingToTwoTree(List> resultList,
- List> listOne,
- List> listTwo, Map authCode) {
- for (int i = 0; i < listOne.size(); i++) {
-
- List> midList = new ArrayList>();
- for (int j = 0; j < listTwo.size(); j++) {
-
- if (listTwo.get(j).get("pid").toString()
- .equals(listOne.get(i).get("id").toString())) {
-
- List> minlist = new ArrayList>();
-
- Map midMap = new HashMap();
- 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 rootMap = new HashMap();
- 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);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
- private void packagingToThreeTree(List> resultList,
- List> listOne,
- List> listTwo,
- List> listThree, Map authCode) {
- for (int i = 0; i < listOne.size(); i++) {
-
- List> midList = new ArrayList>();
- for (int j = 0; j < listTwo.size(); j++) {
-
- if (listTwo.get(j).get("pid").toString()
- .equals(listOne.get(i).get("id").toString())) {
-
- List> minlist = new ArrayList>();
-
- for (int k = 0; k < listThree.size(); k++) {
- Map minMap = new HashMap();
- 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 midMap = new HashMap();
- 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 rootMap = new HashMap();
- 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);
- }
- }
-
-
-
-
-
-
-
-
-
-
- private int validateRightMask(List> list,
- Map 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_detectprop>
- <prop key="template_update_delay">0prop>
- <prop key="default_encoding">UTF-8prop>
- <prop key="output_encoding">UTF-8prop>
- <prop key="locale">zh_CNprop>
- <prop key="date_format">yyyy-MM-ddprop>
- <prop key="time_format">HH:mm:ssprop>
- <prop key="number_format">0.######prop>
- <prop key="datetime_format">yyyy-MM-dd HH:mm:ssprop>
-
- <prop key="classic_compatible">trueprop>
-
- <prop key="auto_import">inc/spring.ftl as baseprop>
- 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>
-
- <property name="allowSessionOverride" value="true"/>
- <property name="exposeRequestAttributes" value="true"/>
- <property name="exposeSessionAttributes" value="true"/>
- <property name="exposeSpringMacroHelpers" value="true"/>
-
- <property name="requestContextAttribute" value="request"/>
-
- <property name="attributesMap">
- <map>
-
- <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());
- int count=0;
- 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>
以上就是对用户的访问模块(权限)进行控制的大体实现。