上一篇关于ACL的文章中:位运算实现ACL授权与认证过程的原理解析,我们学习了通过位运算实现ACL授权与认证的原理核心,今天我们一起来看授权的实例。
实现的功能很简单:打开授权界面时,加载已授权信息。通过点击授权界面上面的复选框,实现授权与取消授权。
下面是Manager层的实现:
package com.lzq.manager.impl; import java.util.List; import com.lzq.model.ACL; /** * 主体授权管理实现 * @author lzq * */ public class ACLManager extends AbstractPageManager { /** * 授权过程 * 添加或更新授权操作 * @param principalType 主体类型 用户或角色 * @param principalSn 主体标识 用户Id或角色Id * @param resourceSn 资源标识 模块Id * @param permission 权限 C/R/U/D 0 1 2 3 * @param yes 是否允许,true表示允许授权;false表示不允许授权 */ public void addOrUpdatePermission(String principalType, int principalSn, int resourceSn, int permission, boolean yes) { //根据主体标识和资源标识查找ACL实例 ACL acl = findACL(principalType, principalSn, resourceSn); //如果存在ACL实例,则更新其授权 if (acl != null) { acl.setPermission(permission, yes); getHibernateTemplate().update(acl); return; } //如果不存在ACL实例,则创建ACL实例 acl = new ACL(); acl.setPrincipalType(principalType); acl.setPrincipalSn(principalSn); acl.setResourceSn(resourceSn); acl.setPermission(permission, yes); getHibernateTemplate().save(acl); } /** * 删除授权 * @param principalType 主体类型 * @param principalSn 主体标识 * @param resourceSn 资源标识 */ public void delPermission(String principalType, int principalSn, int resourceSn) { getHibernateTemplate() .delete ( findACL(principalType, principalSn, resourceSn) ); } /** * 这是在用户授权页面调用的方法 * 设置用户某个资源授权的继承特性 * 添加或更新用户的继承特性 * i. -1继承:这些权限将使用其(即用户)所拥有的角色的权限,而不使用其(即用户)单独设置的权限 * ii. 0表示不继承:这些权限将使用其单独设置的权限,而不使用其所拥有的角色的权限 * @param userId 用户标识 * @param sourceSn 资源标识 模块Id * @param yes true表示继承,false表示不继承 */ public void addOrUpdateUserExtends(int userId, int sourceSn, boolean yes) { //根据主体标识和资源标识查找ACL实例 ACL acl = findACL(ACL.TYPE_USER ,userId, sourceSn); //如果存在ACL实例,则更新其授权 if (yes) { acl.setExtends(yes); getHibernateTemplate().update(acl); return; } //如果不存在ACL实例,则创建ACL实例 acl = new ACL(); acl.setPrincipalType(ACL.TYPE_USER); acl.setPrincipalSn(userId); acl.setResourceSn(sourceSn); acl.setExtends(yes); getHibernateTemplate().save(acl); } /** * 根据主体类型、主体标识、资源标识查找ACL实例 * @param principalType * @param principalSn * @param resourceSn * @param permission * @return */ private ACL findACL(String principalType, int principalSn,int resourceSn){ String strSql ="select acl from ACL acl where acl.principalType = ? and acl.principalSn = ? and acl.resourceSn = ?"; ACL acl =(ACL)getSession().createQuery(strSql) .setParameter(0, principalType) .setParameter(1, principalSn) .setParameter(2, resourceSn) .uniqueResult(); return acl; } /** * 页面加载时,加载所有的授权信息 * @param principalType * @param principalSn * @return */ public List searchACLRecord(String principalType, int principalSn) { String sql = "select resourceSn,aclState&1,aclState&2," + "aclState&4,aclState&8,aclTriState from T_ACL where " + "principalType='"+principalType+"' and principalSn="+principalSn; List aclRecord = getSession().createSQLQuery(sql).list(); return aclRecord; } }
通过DWR,在jsp页面上面调用Manager层的相应的方法,加载时实现对已授权信息的加载,以及用户对权限的动态控制。
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@ include file="/common/common.jsp" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <c:choose> <c:when test="${aclForm.principalType eq 'Role' }"> <c:set var="title" value="请给角色【${role.name }】授权" /> </c:when> <c:otherwise> <c:set var="title" value="请给用户【${user.person.name }】授权" /> </c:otherwise> </c:choose> <title>${title }</title> <link href="style/oa.css" rel="stylesheet" type="text/css"> <script language="javascript" src="script/public.js"></script> <script type="text/javascript" src="dwr/engine.js"></script> <script type="text/javascript" src="dwr/util.js"></script> <script type="text/javascript" src="dwr/interface/aclManager.js"></script> <script type="text/javascript"> //授权 function addOrUpdatePermission(field){ //如果被选择上,则同时选择其"不继承"和"启用"checkbox if(field.checked){ $(field.resourceSn+"_USE").checked = true; <c:if test="${aclForm.principalType eq 'User' }"> $(field.resourceSn+"_EXT").checked = true; </c:if> } aclManager.addOrUpdatePermission( "${aclForm.principalType}", ${aclForm.principalSn}, field.resourceSn, field.permission, field.checked ); } //设置用户的继承特性 function addOrUpdateUserExtends(field){ aclManager.addOrUpdateUserExtends( ${aclForm.principalSn}, field.resourceSn, !field.checked ); } //点击 启用 checkbox function usePermission(field){ //如果checkbox被选中,意味着需要更新ACL的状态 //更新C/R/U/D以及Extends状态 //设置为同步状态,以便DWR依次发出下列请求 dwr.engine.setAsync(false); if(field.checked){ //更新C状态 addOrUpdatePermission($(field.resourceSn+"_C")); //更新R状态 addOrUpdatePermission($(field.resourceSn+"_R")); //更新U状态 addOrUpdatePermission($(field.resourceSn+"_U")); //更新D状态 addOrUpdatePermission($(field.resourceSn+"_D")); //更新Extends状态 <c:if test="${aclForm.principalType eq 'User' }"> addOrUpdateUserExtends($(field.resourceSn+"_EXT")); </c:if> }else{ //如果不启用,则删除授权信息 aclManager.delPermission( "${aclForm.principalType}", ${aclForm.principalSn}, field.resourceSn ); //并且在界面上去掉相应的CRUD选择的选项 $(field.resourceSn+"_C").checked = false; $(field.resourceSn+"_R").checked = false; $(field.resourceSn+"_U").checked = false; $(field.resourceSn+"_D").checked = false; <c:if test="${aclForm.principalType eq 'User' }"> $(field.resourceSn+"_EXT").checked = false; </c:if> } } //打开界面时,从数据库中加载授权信息 function initTable(){ aclManager.searchACLRecord( "${aclForm.principalType}", ${aclForm.principalSn}, function(datas){ for(var i=0;i<datas.length;i++){ var resourceSn =datas[i][0]; var cState = datas[i][1]; var rState = datas[i][2]; var uState = datas[i][3]; var dState = datas[i][4]; var extState = datas[i][5]; $(resourceSn+"_C").checked =cState ==0 ? false : true; $(resourceSn+"_R").checked =rState ==0 ? false : true; $(resourceSn+"_U").checked =uState ==0 ? false : true; $(resourceSn+"_D").checked =dState ==0 ? false : true; //等于0,不继承,就要选择上,所以为true <c:if test="${aclForm.principalType eq 'User' }"> $(resourceSn+"_EXT").checked=extState ==0 ? true : false; </c:if> $(resourceSn+"_USE").checked = true; } } ); } </script> </head> <body onload="initTable()"> <form action="person.do"> <TABLE class="tableEdit" border="0" cellspacing="1" cellpadding="0" style="580px;"> <TBODY> <TR> <td> <table class="tableEdit" style="580px;" cellspacing="0" border="0" cellpadding="0"> <tr> <!-- tdEditContent --> <td class="tdEditLabel" >顶级模块</td> <td class="tdEditContent">二级模块</td> <td class="tdEditLabel">权限</td> <c:if test="${aclForm.principalType eq 'User' }"> <td class="tdEditLabel">不继承</td> </c:if> <td class="tdEditLabel">启用</td> </tr> <!-- 输出模块树 --> <c:forEach items="${moduleList }" var="module"> <tr> <td>${module.name }</td> <td> </td> <td> <input type="checkbox" id="${module.id }_C" resourceSn="${module.id }" permission="0" onclick="addOrUpdatePermission(this)">C <input type="checkbox" id="${module.id }_R" resourceSn="${module.id }" permission="1" onclick="addOrUpdatePermission(this)">R <input type="checkbox" id="${module.id }_U" resourceSn="${module.id }" permission="2" onclick="addOrUpdatePermission(this)">U <input type="checkbox" id="${module.id }_D" resourceSn="${module.id }" permission="3" onclick="addOrUpdatePermission(this)">D </td> <c:if test="${aclForm.principalType eq 'User' }"> <td> <input type="checkbox" id="${module.id }_EXT" resourceSn="${module.id }" onclick="addOrUpdateUserExtends(this)"> </td> </c:if> <td> <input type="checkbox" id="${module.id }_USE" resourceSn="${module.id }" onclick="usePermission(this)"> </td> </tr> <c:forEach items="${module.children }" var="child"> <tr> <td> </td> <td>${child.name }</td> <td> <input type="checkbox" id="${child.id }_C" resourceSn="${child.id }" permission="0" onclick="addOrUpdatePermission(this)">C <input type="checkbox" id="${child.id }_R" resourceSn="${child.id }" permission="1" onclick="addOrUpdatePermission(this)">R <input type="checkbox" id="${child.id }_U" resourceSn="${child.id }" permission="2" onclick="addOrUpdatePermission(this)">U <input type="checkbox" id="${child.id }_D" resourceSn="${child.id }" permission="3" onclick="addOrUpdatePermission(this)">D </td> <c:if test="${aclForm.principalType eq 'User' }"> <td> <input type="checkbox" id="${child.id }_EXT" resourceSn="${child.id }" onclick="addOrUpdateUserExtends(this)"> </td> </c:if> <td><input type="checkbox" id="${child.id }_USE" onclick="usePermission(this)" resourceSn="${child.id }"></td> </tr> </c:forEach> </c:forEach> </table> </td> </TR> </TBODY> </TABLE> </form> </body> </html>
下面是通过点击角色授权或者用户授权,进入的授权界面:
这个过程说难不难,说简单也不简单。我认为这个功能的主要亮点有:
1、对多选框的动态控制;
2、巧妙的使用位运算完成授权与认证。