您的位置:首页 > 其它

跟着汤阳光同志做一个OA系统(九):权限模块

2015-12-10 08:37 302 查看
权限:

控制功能的使用

Web应用中的权限:

l 权限就是控制功能的使用(功能对应着URL)。

l 对功能的控制就是对URL的访问控制。

l 在我们的程序中,一个功能对应一个或两个URL:

• 1,例如列表或删除功能,只对应一个URL.

• 2,例如添加或修改功能,对应两个URL:..add, ..addUI

权限方案:

用户 *----*
角色 *----*
权限






与权限相关的功能具体有哪些:

l 初始化数据就做一次,通过写一个安装文件,利用hibernate实现跨数据库安装)

• 权限数据。权限数据是不能增删改的,由你的系统决定,有哪些功能就有哪些权限,在安装的时候就确定。

• 超级管理员。超级管理员担负最初为别人分配权限的职责。一般有权限的系统都有超级管理员,他拥有所有的权限,并且别人不能删除他的权限。

l 分配权限

• 给角色分配权限。

• 用户的权限就是用户所有角色的权限。

l 使用权限

• 1,登录、注销、主页面。

• 2,左侧的菜单是根据权限显示的。

• 3,右侧页面中的链接是根据权限显示的。

• 4,拦截每一个action请求,验证用户是否有权限访问。

权限的分类



权限类设计

public class Privilege implementsjava.io.Serializable{

private Long id;

private String url;

private String name; //
权限名称


private Set<Role>roles = new HashSet<Role>();//与角色(岗位)的关系

private Privilege parent;//
上级权限


privateSet<Privilege> children = new HashSet<Privilege>(); //
下级权限


public Privilege() {

}

public Privilege(Stringname, String url, Privilege parent) {

this.name =name;

this.url = url;

this.parent =parent;

}

。。。

}

权限是根据系统的功能确定的,你有什么样的功能,需要怎么样控制,在你的系统确定之后就被定死了,权限数据也就确定了。可以通过一个安装文件一键写入数据。当然也可以通过写脚本的方式。

/**

*本文件是用于系统初始化数据的,在安装的时候执行一遍

*/

@Component

public class Installer {

@Resource

private SessionFactorysessionFactory;

/**

*
执行安装


*/

@Transactional

public void install() {

Session session= sessionFactory.getCurrentSession();

System.out.println("开始安装系统数据");

//==============================================================

//
保存超级管理员用户


User user = newUser();

user.setLoginName("admin");

user.setName("超级管理员");

user.setPassword(DigestUtils.md5Hex("admin"));

session.save(user);//
保存


System.out.println("超级管理员安装完毕");

//==============================================================

//
保存权限数据


Privilege menu,menu1, menu2, menu3, menu4, menu5;

//--------------------

menu = newPrivilege("系统管理", null,null);

menu1 = new Privilege("岗位管理","/role_list", menu);

menu2 = newPrivilege("部门管理","/department_list", menu);

menu3 = newPrivilege("用户管理","/user_list", menu);

session.save(menu);

session.save(menu1);

session.save(menu2);

session.save(menu3);

session.save(newPrivilege("岗位列表","/role_list", menu1));

session.save(newPrivilege("岗位删除","/role_delete", menu1));

session.save(newPrivilege("岗位添加","/role_add", menu1));

session.save(newPrivilege("岗位修改","/role_edit", menu1));

session.save(newPrivilege("部门列表","/department_list", menu2));

session.save(newPrivilege("部门删除","/department_delete", menu2));

session.save(newPrivilege("部门添加","/department_add", menu2));

session.save(newPrivilege("部门修改","/department_edit", menu2));

session.save(newPrivilege("用户列表","/user_list", menu3));

session.save(newPrivilege("用户删除","/user_delete", menu3));

session.save(newPrivilege("用户添加","/user_add", menu3));

session.save(newPrivilege("用户修改","/user_edit", menu3));

session.save(newPrivilege("初始化密码","/user_initPassword", menu3));

//--------------------

menu = newPrivilege("网上交流", null,null);

menu1 = newPrivilege("论坛管理","/forumManage_list", menu);

menu2 = newPrivilege("论坛","/forum_list", menu);

session.save(menu);

session.save(menu1);

session.save(menu2);

//--------------------

menu = newPrivilege("审批流转", null,null);

menu1 = newPrivilege("审批流程管理","/processDefinition_list", menu);

menu2 = newPrivilege("申请模板管理","/template_list", menu);

menu3 = new Privilege("起草申请","/flow_templateList", menu);

menu4 = newPrivilege("待我审批","/flow_myTaskList", menu);

menu5 = newPrivilege("我的申请查询","/flow_myApplicationList", menu);

session.save(menu);

session.save(menu1);

session.save(menu2);

session.save(menu3);

session.save(menu4);

session.save(menu5);

System.out.println("权限数据安装完毕");

}

public static voidmain(String[] args) {

ApplicationContextac = new ClassPathXmlApplicationContext("applicationContext.xml");

Installerinstaller = (Installer) ac.getBean("installer");

installer.install();

}

}

User中添加判断权限的方法

/**

*
判断本用户是否有指定URL的权限


*

* @param privUrl

* @return

*/

public booleanhasPrivilegeByUrl(String privUrl) {

//
超级管理有所有的权限


if (isAdmin()) {

returntrue;

}

// >>
去掉后面的参数


int pos =privUrl.indexOf("?");

if (pos > -1){

privUrl= privUrl.substring(0, pos);

}

// >>
去掉UI后缀


if(privUrl.endsWith("UI")) {

privUrl= privUrl.substring(0, privUrl.length() - 2);

}

//
如果本URL不需要控制,则登录用户就可以使用


Collection<String>allPrivilegeUrls = (Collection<String>)ActionContext.getContext().getApplication().get("allPrivilegeUrls");

if(!allPrivilegeUrls.contains(privUrl)) {//本地址不在所有要控制的地址中(就是要控制的功能),不控制那么我登陆之后就能使用


returntrue;


} else {

//
普通用户要判断是否含有这个权限


for(Role role : roles) {


for(Privilege priv : role.getPrivileges()) {



if(privUrl.equals(priv.getUrl())) {



returntrue;



}



}


}

returnfalse;

}

}

/**

*
判断本用户是否有指定名称的权限


*

* @param name

* @return

*/

public booleanhasPrivilegeByName(String name) {

//
超级管理有所有的权限


if (isAdmin()) {

returntrue;

}

//
普通用户要判断是否含有这个权限


for (Role role :roles) {

for(Privilege priv : role.getPrivileges()) {


if(priv.getName().equals(name)) {



returntrue;



}


}

}

return false;

}

/**

*
判断本用户是否是超级管理员


*

* @return

*/

public boolean isAdmin() {

return"admin".equals(loginName);

}

左边的菜单是根据用户的权限显示的

<ul id="MenuUl">


<%-- 显示一级菜单 --%>



<s:iteratorvalue="#application.topPrivilegeList">



<!--循环所有的权限,我有这个权限那就显示:在用户中增加一个判断是否有顶级权限,name就是权限的名字 -->



<s:iftest="#session.user.hasPrivilegeByName(name)">



<liclass="level1">



<divonClick="menuClick(this);" class="level1Style">



<!-- 通过id和图片的名字结合起来这个技巧简单的实现不同的菜单不同的图片
-->



<imgsrc="style/images/MenuIcon/${id}.gif" class="Icon" />



${name}



</div>



<ulstyle="" class="MenuLevel2" id="aa">



<%--显示二级菜单 --%>



<s:iteratorvalue="children">



<!-- 在用户中增加一个判断是否有二级权限,name就是权限的名字 -->



<s:iftest="#session.user.hasPrivilegeByName(name)">



<liclass="level2">



<divclass="level2Style">



<imgsrc="style/images/MenuIcon/menu_arrow_single.gif" />



<atarget="right" href="${pageContext.request.contextPath}${url}.action"> ${name}</a>



</div>



</li>



</s:if>



</s:iterator>



</ul>



</li>



</s:if>



</s:iterator>


</ul>

添加ServletContextListener在Tomcat启动的时候就执行一次,把需要准备的权限准备好。

/**

*
这个监听器是由tomcat通过反射生成的实例


*
与spring的容器无关,所以通过注解是不能注入对象给这个容器的,


*
加上component注解之后,spring也会生成实例,但是与这个实例没关系


*
所以要通过WebApplicationContextUtils获取spring的容器对象+


* @author
熊诗言


*

*/

public class InitListener implements ServletContextListener {

public voidcontextInitialized(ServletContextEvent sce) {

//
获取容器与相关的Service对象


ApplicationContextac =
WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());


PrivilegeServiceprivilegeService = (PrivilegeService)ac.getBean("privilegeServiceImpl");

//
准备数据:topPrivilegeList,用于显示左边的菜单(有权限才显示)


/***

*
这里由于在页面中需要访问privilege的children属性,如果用了懒加载特性,


*
即是使用了Spring的OpensessionInViewFilter,也不好使。因为这个对象是在监听器中而非请求中获取到的,


*
获取到之后session就关闭了。比如容器启动后很久才有人访问,访问的时候jsp中获取children属性就会出现懒加载问题。


*
所以在这里必须把懒加载的特性关闭。


*

*
过滤器只能解决同一个请求的懒加载问题,懒加载异常的根本就是session关闭


*/

List<Privilege>topPrivilegeList = privilegeService.findTopList();

sce.getServletContext().setAttribute("topPrivilegeList",topPrivilegeList);

System.out.println("------------>已准备好顶级菜单topPrivilegeList<------------");

//
准备数据:allPrivilegeUrls,这是所有需要控制的url,在这个集合中的所有都需要控制,你的权限中有这个url,那么你能访问,否则不能访问,没在这个集合中的你都能访问,比如主页、注销。


Collection<String>allPrivilegeUrls = privilegeService.getAllPrivilegeUrls();

sce.getServletContext().setAttribute("allPrivilegeUrls",allPrivilegeUrls);

System.out.println("------------>已准备菜单超链接allPrivilegeUrls<------------");

}

public voidcontextDestroyed(ServletContextEvent arg0) {

}

}

在web.xml中注明listner

<!-- spring的初始化容器的监听器 -->

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext*.xml</param-value>

</context-param>

<!--

用于做初始化工作的监听器,一定要配置到Spring的ContextLoaderListener之后,因为要用到Spring的容器对象

-->

<listener>

<listener-class>com.xsy.oa.utils.InitListener</listener-class>

</listener>

右边的链接是根据是否有这个权限显示的

packageorg.apache.struts2.views.jsp.ui;

。。。

/**

*这个自定义标签用于覆盖struts2的a标签(因为包名类名都一样),

*会先在classpath下找到这个类,然后就不会再在jar包中找。

*从tld文件中找到标签的声明定位到这个类。

*

*其实更保险的做法就是生成jar之后考入jar包覆盖原来的文件

*或者完全自定义标签(用新的prefix)

* @see Anchor

*/

public class AnchorTag extends AbstractClosingTag {

。。。

@Override

public int doEndTag()throws JspException {

//
当前登录用户


User user = (User)pageContext.getSession().getAttribute("user");

//
当前准备显示的链接对应的权限URL


// >>
在开头加上'/'


String privUrl ="/" + action;

if (user.hasPrivilegeByUrl(privUrl)){

returnsuper.doEndTag(); //
正常的生成并显示超链接标签,并继续执行页面中后面的代码


} else {

returnEVAL_PAGE; //
不生成与显示超链接标签,只是继续执行页面中后面的代码


}

}

。。。

}

根据权限显示并不是终极目标,因为我还是可以通过直接访问地址的方式访问你的功能,最重要的就是通过拦截器拦截所有的action,判断权限。

public class CheckPrivilegeInterceptor extends AbstractInterceptor {

public Stringintercept(ActionInvocation invocation) throws Exception {

//System.out.println("--------->
之前");


// String result= invocation.invoke(); //
放行


//System.out.println("--------->
之后");


// returnresult;

//
获取信息


User user =(User) ActionContext.getContext().getSession().get("user"); //
当前登录用户


String namespace= invocation.getProxy().getNamespace();

StringactionName = invocation.getProxy().getActionName();

String privUrl =namespace + actionName; //
对应的权限URL


//
如果未登录


if (user ==null) {

if(privUrl.startsWith("/user_login")) { // "/user_loginUI","/user_login"


//如果是去登录,就放行



returninvocation.invoke();


} else{


//如果不是去登录,就转到登录页面



return"loginUI";


}

}else {//
如果已登录,就判断权限


if(user.hasPrivilegeByUrl(privUrl)) {


//如果有权限,就放行



returninvocation.invoke();


} else{


//如果没有权限,就转到提示页面



return"noPrivilegeError";


}

}

}

}

分配权限的权限树

<%@ page language="java" import="java.util.*"pageEncoding="utf-8"%>

<html>

<head>

<title>配置权限</title>

<%@ includefile="/WEB-INF/jsp/public/commons.jspf" %>

<scriptlanguage="javascript"src="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.js"></script>

<linktype="text/css" rel="stylesheet"href="${pageContext.request.contextPath}/style/blue/file.css" />

<linktype="text/css" rel="stylesheet"href="${pageContext.request.contextPath}/script/jquery_treeview/jquery.treeview.css"/>

<script type="text/javascript">

$(function(){

//
指定事件处理函数


$("[name=privilegeIds]").click(function(){


//当选中或取消一个权限时,也同时选中或取消所有的下级权限



$(this).siblings("ul").find("input").attr("checked",this.checked);



//当选中一个权限时,也要选中所有的直接上级权限



if(this.checked== true){



$(this).parents("li").children("input").attr("checked",true);



}


});

});

</script>

</head>

<body>

<!-- 标题显示 -->

<div id="Title_bar">

<divid="Title_bar_Head">

<divid="Title_Head"></div>

<divid="Title"><!--页面标题-->

<imgborder="0" width="13" height="13"src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/>配置权限

</div>

<divid="Title_End"></div>

</div>

</div>

<!--显示表单内容-->

<div id=MainArea>

<s:formaction="role_setPrivilege">

<s:hidden name="id"></s:hidden>

<divclass="ItemBlock_Title1"><!--
信息说明 --><divclass="ItemBlock_Title1">


<img border="0" width="4"height="7"src="${pageContext.request.contextPath}/style/blue/images/item_point.gif"/>
正在为【${name}】配置权限 </div>


</div>

<!--
表单内容显示 -->


<divclass="ItemBlockBorder">

<divclass="ItemBlock">

<tablecellpadding="0" cellspacing="0"class="mainForm">


<!--表头-->



<thead>



<tralign="LEFT" valign="MIDDLE" id="TableTitle">



<tdwidth="300px" style="padding-left: 7px;">



<!--如果把全选元素的id指定为selectAll,并且有函数selectAll(),就会有错。因为有一种用法:可以直接用id引用元素
-->



<inputtype="checkbox" id="cbSelectAll"onClick="$('[name=privilegeIds]').attr('checked', this.checked)"/>



<labelfor="cbSelectAll">全选</label>



</td>



</tr>



</thead>


<!--显示数据列表-->


<tbodyid="TableData">



<trclass="TableDetail1">



<!--显示权限树 -->



<td>


<!-- 使用它的目的是为了回显,但是换行都做不了

<s:checkboxlistname="privilegeIds" list="#privilegeList"listKey="id" listValue="name"></s:checkboxlist>

-->

<%-- 自己实现回显和换行

<s:iteratorvalue="#privilegeList">

<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}"

<s:propertyvalue="%{id in privilegeIds ? 'checked' : ''}"/>

/>

<labelfor="cb_${id}">${name}</label>

<br/>

</s:iterator>

--%>

<!—通过treeview控件显示树状结构内容
-->


<ul id="tree">

<s:iteratorvalue="#application.topPrivilegeList">

<li>

<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />

<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>

<ul>

<s:iteratorvalue="children">


<li>



<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />



<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>



<ul>



<s:iteratorvalue="children">



<li>



<inputtype="checkbox" name="privilegeIds" value="${id}"id="cb_${id}" <s:property value="%{id in privilegeIds ?'checked' : ''}"/> />



<labelfor="cb_${id}"><spanclass="folder">${name}</span></label>



</li>



</s:iterator>



</ul>



</li>


</s:iterator>

</ul>

</li>

</s:iterator>

</ul>


</td>



</tr>



</tbody>


</table>

</div>

</div>

<!--
表单操作 -->


<divid="InputDetailBar">

<inputtype="image"src="${pageContext.request.contextPath}/style/images/save.png"/>

<ahref="javascript:history.go(-1);"><imgsrc="${pageContext.request.contextPath}/style/images/goBack.png"/></a>

</div>

</s:form>

</div>

</body>

</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: