`
fengfeng925
  • 浏览: 107109 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

基于Struts2拦截器的权限控制

阅读更多
    最近闲来无事,自己做了个通过struts2拦截器的权限控制的小例子。主要是通过struts2的核心拦截器机制,不依赖于容器,实现一个可以精确到方法上的细粒度的权限控制。

     该小例子借鉴了网上一些前辈们,还有学界同行们的项目经验,我取其优秀的部分,稍加加工,改造而成,还非常不完善,欢迎大家批评指正。该小例子只供学习交流,无意于商业化中使用,也无意于挑起任何争端。

    下面是一些类的代码,这里可能需要大家对注解比较熟悉,不过不熟悉也不影响,和xml配置文件起的是一样的作用,都是将属性映射成为表的字段。

首先呢,建立一个注解类,名字叫Permission。这个注解类的代码如下
package com.zxyg.web.action.privilege;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 权限配置 注解类
 * @author Lan
 *
 */
@Retention(RetentionPolicy.RUNTIME) //注解的存活时间,整个运行时都存活
@Target(ElementType.METHOD) //此注解表示只能在方法上面有效
public @interface Permission {
	/** 模块名 **/
	String model();
	/** 权限值 **/
	String privilegeValue();
}

这个类,就是将来要在方法上打标记的。

接下来要建立几个跟权限相关的实体类了。
首先是权限实体类,类的代码如下
package com.zxyg.bean.privilege;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * 系统权限实体
 * @author Lan
 * 
 */
@Entity
@Table(name="t_systemprivilege")
public class SystemPrivilege {
	/** 权限值**/
	private SystemPrivilegePK id;
	/** 权限名称**/
	private String name;
	
	public SystemPrivilege() {}

	public SystemPrivilege(SystemPrivilegePK id) {
		this.id = id;
	}

	public SystemPrivilege(String model, String privilegeValue, String name) {
		this.id = new SystemPrivilegePK(model, privilegeValue);
		this.name = name;
	}

	@EmbeddedId //复合主键的标注
	public SystemPrivilegePK getId() {
		return id;
	}

	public void setId(SystemPrivilegePK id) {
		this.id = id;
	}

	@Column(length=20, nullable=false)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

这个类主要包含两个属性,一个是权限值,另外一个是权限的名称,权限值呢,实际也是一个类,这里采用的是复合主键的形式,权限值的实体类代码如下
package com.zxyg.bean.privilege;

import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
 * 系统权限复合主键类
 * @author Lan
 * 
 */
@Embeddable
public class SystemPrivilegePK {
	/** 模块名 **/
	private String model;
	/** 权限值 **/
	private String privilegeValue;
	
	public SystemPrivilegePK() {}

	public SystemPrivilegePK(String model, String privilegeValue) {
		this.model = model;
		this.privilegeValue = privilegeValue;
	}

	@Column(length=25, name="model")
	public String getModel() {
		return model;
	}

	public void setModel(String model) {
		this.model = model;
	}

	@Column(length=20, name="privilegeValue")
	public String getPrivilegeValue() {
		return privilegeValue;
	}

	public void setPrivilegeValue(String privilegeValue) {
		this.privilegeValue = privilegeValue;
	}
}


这个类有两个属性,一个是模块的名称,一个是模块对应的值。其实呢,这里在数据库里面的权限表里存储的就是对某个资源的什么操作,描述名称是什么,比如
role delete 角色删除
意思就是对role这个模块的删除操作,这个呢,就是一个具体的权限。
最后一个实体类就比较简单了,是角色类,类代码如下
package com.zxyg.bean.privilege;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import com.zxyg.bean.organization.Employee;


/**
 * 角色实体
 * @author Lan
 * 
 */
@Entity
@Table(name="t_role")
public class Role {
	/** 主键ID* */
	private Integer id;
	/** 角色名称* */
	private String name;
	/** 存放权限的集合,角色和权限是多对多的关系 * */
	private Set<SystemPrivilege> privileges = new HashSet<SystemPrivilege>();
	
	public Role() {}
	
	public Role(Integer id) {
		this.id = id;
	}

	@Id @GeneratedValue
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(length=20, nullable=false)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@ManyToMany(cascade=CascadeType.REFRESH, fetch=FetchType.EAGER)
	@JoinTable(name="t_role_privilege", joinColumns=@JoinColumn(name="roleid"),
			inverseJoinColumns={@JoinColumn(name="model", referencedColumnName="model"),
		                        @JoinColumn(name="privilegeValue", referencedColumnName="privilegeValue")}) //中间表,来存放角色、权限的关系
	public Set<SystemPrivilege> getPrivileges() {
		return privileges;
	}

	public void setPrivileges(Set<SystemPrivilege> privileges) {
		this.privileges = privileges;
	}
	
	//定义此方法,方便添加权限
	public void addPrivilege(SystemPrivilege privilege) {
		this.privileges.add(privilege);
	}
}


这个类就比较简单了,具体看一下其中的关系即可,这里就不多做赘述了。
当你有一个Action类的时候,需要在方法上加标注描述了。举例如下
package com.zxyg.web.action.privilege;

import java.io.Serializable;

import javax.annotation.Resource;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;


import com.opensymphony.xwork2.ActionContext;
import com.zxyg.bean.privilege.Role;
import com.zxyg.bean.privilege.SystemPrivilege;
import com.zxyg.bean.privilege.SystemPrivilegePK;
import com.zxyg.service.privilege.RoleService;
import com.zxyg.service.privilege.SystemPrivilegeService;
import com.zxyg.utils.SiteUrl;
import com.zxyg.web.action.base.BaseSupport;

@Controller @Scope("prototype")
public class RoleManageAction extends BaseSupport {
	private static final long serialVersionUID = 1L;
	@Resource private RoleService roleService;
	@Resource private SystemPrivilegeService privilegeService;
	private Role role;
	
	//接收前端传过来的权限数组,如"角色添加"、"角色删除"等
	private SystemPrivilegePK[] privileges;
	
	//接收前端传过来的roleid参数
	private Integer roleid;
	
	public Integer getRoleid() {
		return roleid;
	}

	public void setRoleid(Integer roleid) {
		this.roleid = roleid;
	}

	public SystemPrivilegePK[] getPrivileges() {
		return privileges;
	}

	public void setPrivileges(SystemPrivilegePK[] privileges) {
		this.privileges = privileges;
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}


	/**
	 * 显示角色添加页面
	 * @return
	 */
	@Permission(model="role", privilegeValue="insert")
	public String addUI() {
		ActionContext.getContext().put("privileges", privilegeService.getScrollData().getResultlist());
		return "add";
	}
	
	/**
	 * 添加角色
	 * @return
	 */
	@Permission(model="role", privilegeValue="insert")
	public String add() {
		for(SystemPrivilegePK id : privileges) {
			role.addPrivilege(new SystemPrivilege(id));
		}
		roleService.save(role);
		ActionContext context = ActionContext.getContext();
		context.put("message", "添加角色成功");
		context.put("urladdress", SiteUrl.readUrl("control.role.list"));
		return "message";
	}
	
	/**
	 * 显示角色修改页面
	 * @return
	 */
	@Permission(model="role", privilegeValue="update")
	public String updateUI() {
		role = roleService.find((Serializable)roleid);
		ActionContext context = ActionContext.getContext();
		context.put("role", role);
		context.put("privileges", privilegeService.getScrollData().getResultlist());
		context.put("selectprivileges", role.getPrivileges());
		return "edit";
	}
	
	/**
	 * 修改角色
	 * @return
	 */
	@Permission(model="role", privilegeValue="update")
	public String update() {
		Role old_role = roleService.find((Serializable)roleid);
		old_role.setName(role.getName());
		old_role.getPrivileges().clear();
		for(SystemPrivilegePK id : privileges) {
			old_role.addPrivilege(new SystemPrivilege(id));
		}
		roleService.update(old_role);
		ActionContext context = ActionContext.getContext();
		context.put("message", "修改角色成功");
		context.put("urladdress", SiteUrl.readUrl("control.role.list"));
		return "message";
	}
	
	/**
	 * 删除角色
	 * @return
	 */
	@Permission(model="role", privilegeValue="delete")
	public String delete() {
		roleService.delete((Serializable)roleid);
		ActionContext context = ActionContext.getContext();
		context.put("message", "删除角色成功");
		context.put("urladdress", SiteUrl.readUrl("control.role.list"));
		return "message";
	}
}

看到这些方法上面的描述了吧,其实最终是要取得这些标注描述再来判断权限的。呵呵,接下来我们就写个拦截器了,这里面就是具体描述,当用户登录后如何和这些方法上的标注相互比对进行权限控制的,拦截器代码如下:
package com.zxyg.web.action.privilege;

import java.lang.reflect.Method;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.zxyg.bean.organization.Employee;
import com.zxyg.bean.privilege.Role;
import com.zxyg.bean.privilege.SystemPrivilege;
import com.zxyg.bean.privilege.SystemPrivilegePK;
import com.zxyg.utils.SiteUrl;

/**
 * 使用拦截器进行系统权限的拦截
 * @author Lan
 * 
 */
public class PermissionInterceptor implements Interceptor {
	private static final long serialVersionUID = 1L;

	public void destroy() {}

	public void init() {}

	/**
	 * 处理权限拦截
	 */
	public String intercept(ActionInvocation invocation) throws Exception {
		Employee employee = (Employee) ServletActionContext.getRequest().getSession().getAttribute("employee"); //取得当前登录的用户
		if (validate(employee, invocation)) {
			return invocation.invoke();
		}
		ActionContext context = ActionContext.getContext();
		context.put("message", "你没有权限执行该操作");
		context.put("urladdress", SiteUrl.readUrl("control.center.right"));
		return "message";
	}

	/**
	 * 校验控制在方法上的拦截
	 */
	public boolean validate(Employee employee, ActionInvocation invocation) {
		String methodName= "execute"; //定义默认的访问方法
		Method currentMethod = null;
		methodName = invocation.getProxy().getMethod(); //通过actionProxy,得到当前正在执行的方法名
		try {
			currentMethod = invocation.getProxy().getAction().getClass().getMethod(methodName, new Class[] {}); //利用反射,通过方法名称得到具体的方法
			/*Method[] methods = invocation.getProxy().getAction().getClass().getMethods(); //如果不确定方法的具体参数,也可以迭代比较,速度较慢
			for(Method method : methods ) {
				if(method.getName().equals(methodName)) {
					currentMethod = method;
					break;
				}
			}*/
		} catch (Exception e) {
		}
		if (currentMethod != null && currentMethod.isAnnotationPresent(Permission.class)) {
			Permission permission = currentMethod.getAnnotation(Permission.class); //得到方法上的Permission注解
			SystemPrivilege privilege = new SystemPrivilege(new SystemPrivilegePK(permission.model(), permission.privilegeValue())); //通过Permission注解构造出系统权限
			for (Role role : employee.getRoles()) { //迭代用户所具有的具体权限,如果包含,返回true
				if (role.getPrivileges().contains(privilege)) 
					return true;
			}
			return false;
		}
		return true;
	}

}

这些代码呢,其实已经简单的描述了下,就是将用户存储在数据库中间表中的角色对应的权限取出来,在构造出用户想访问的action中方法上的权限描述,相互比对,如果包含,则可以访问,否则没有权限访问。

最后就是struts.xml文件的配置了,配置好拦截器,就都搞定了,配置文件如下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<package name="privilege" namespace="/control/role" extends="struts-default">
		<interceptors>
			<!-- 定义权限拦截器 -->
			<interceptor name="permission" class="com.zxyg.web.action.privilege.PermissionInterceptor"/>
			<!-- 定义拦截器栈,所谓拦截器栈,是指由一个或多个拦截器组成 -->
			<interceptor-stack name="permissionStack">
				<!-- struts2提供的拦截器栈,包含了struts2的很多核心拦截器 -->
				<interceptor-ref name="defaultStack" />
				<!-- 自己定义的放在最后面,struts2定义的放在前面 -->
				<interceptor-ref name="permission" />
			</interceptor-stack>
		</interceptors>
		
		<!-- 为此包下的所有action应用拦截器 -->
		<default-interceptor-ref name="permissionStack" />
		
		<global-results>
			<result name="message">/WEB-INF/page/share/message.jsp</result>
		</global-results>
		
		<!-- 显示角色列表 -->
		<action name="list" class="roleListAction" method="execute">
			<result name="success">/WEB-INF/page/privilege/rolelist.jsp</result>
		</action>
		
		<!-- 角色管理 -->
		<action name="manage_*" class="roleManageAction" method="{1}">
			<result name="add">/WEB-INF/page/privilege/addrole.jsp</result>
			<result name="edit">/WEB-INF/page/privilege/editrole.jsp</result>
		</action>
	</package>
</struts>

ok,到这里的时候,所有工作就完成了,当用户登录后,就可以进行访问进行权限拦截了的试验了。
2
6
分享到:
评论
6 楼 飘渺孤独 2012-09-03  
给发个源码吧 谢谢了 正在学习中
250227642@qq.com
5 楼 itoao 2011-12-23  
itoao 写道
请问能发份源码给我么 谢谢 非常感谢 最近需要用这个。

忘记给邮箱了  liangsantian@yeah.net  感激不尽!!
4 楼 itoao 2011-12-23  
请问能发份源码给我么 谢谢 非常感谢 最近需要用这个。
3 楼 catmimigo 2011-09-21  
看了您的文章后,对自定义注解十分感兴趣,能否发份源码给我,就要用户角色权限RBAC这一块。包括SQL.麻烦您了。catmimigo@msn.com
2 楼 lqysaber 2011-01-10  
可否将完整源码分享一下阿,不胜感激 kbtjhvb@yeah.net
1 楼 gyl868 2010-06-17  
很喜欢楼主的设计思路,可否将完整源码分享一下阿,不胜感激 gyl8680@gmail.com

相关推荐

    Struts2拦截器实现权限控制demo

    通过以上步骤,我们可以实现一个基本的基于Struts2拦截器的权限控制系统。这个demo对于初学者来说,是一个很好的起点,可以帮助他们理解如何在实际项目中结合Struts2的拦截器和权限控制来增强应用的安全性。在实际...

    struts2拦截器实现权限控制

    在Struts2中,拦截器是基于AOP(面向切面编程)的概念设计的,它们在Action调用前后执行,可以添加额外的功能,如日志记录、事务管理、权限验证等。对于权限控制,拦截器可以在请求到达Action之前检查用户的登录状态...

    Struts2拦截器及其用法详细说明

    在Struts2中,拦截器(Interceptors)扮演着核心角色,增强了框架的功能和灵活性。这篇文章将深入探讨Struts2拦截器的概念、工作原理以及如何在实际应用中使用它们。 **一、什么是Struts2拦截器** 拦截器是基于AOP...

    struts2 拦截器

    Struts2的拦截器是基于Java的Servlet Filter机制实现的,但是更加强大和灵活。 2. **拦截器链**:在Struts2中,多个拦截器可以形成一个拦截器链,每个拦截器按照定义的顺序依次执行。如果所有拦截器都允许Action...

    struts2拦截器

    描述中提到的“基于struts2的拦截器测试,实现了页面的跳转,中间过程的拦截”,这表明我们可能在创建一个测试场景,来验证拦截器如何控制请求的流向以及如何在特定的业务逻辑点进行干预。页面跳转通常是拦截器完成...

    使用struts2拦截器对登陆权限验证

    在Struts2中,拦截器(Interceptor)扮演着至关重要的角色,它允许开发者在动作执行前后插入自定义逻辑,如日志记录、权限验证等。在本案例中,我们将深入探讨如何使用Struts2拦截器实现登录权限验证,同时结合...

    struts2 拦截器实例

    在Struts2中,拦截器(Interceptor)扮演着核心角色,它们允许开发者在Action执行前后插入自定义的逻辑,如日志、权限检查、事务管理等。现在我们将深入探讨Struts2的拦截器机制及其实例应用。 ### 一、Struts2拦截...

    Struts2 拦截器

    Struts2的拦截器基于AOP(面向切面编程)思想,允许开发者在不修改原有代码的情况下添加额外的功能。 在Struts2中,拦截器是基于Java的动态代理机制实现的。当你定义一个拦截器时,实际上创建了一个实现了`...

    Struts2权限控制

    "基于Struts2拦截器的权限控制.doc"文档很可能是提供了一个具体的案例,详细讲解了如何创建并使用拦截器进行权限控制。文档可能会涵盖以下内容: 1. 创建自定义拦截器类,实现`Interceptor`接口,重写`intercept()`...

    Struts2拦截器原理分析

    在文章"Struts2拦截器原理分析实例"中,作者通过一个具体的应用场景,展示了如何配置和使用拦截器来实现特定的功能,比如日志记录或权限验证。通过阅读这篇博客,我们可以更直观地理解拦截器的工作方式和价值。 ...

    struts2拦截器控制权限

    在Struts2中,拦截器(Interceptor)是实现业务逻辑控制和增强功能的重要组件,尤其是在权限控制方面。本文将深入探讨Struts2拦截器如何帮助我们实现精细的权限控制,并通过实际例子进行说明。 首先,理解Struts2...

    struts2 拦截器实现登录控制

    这篇博客“struts2 拦截器实现登录控制”显然会探讨如何利用拦截器来实现用户登录验证,从而保护应用程序的受保护资源。 首先,我们了解下Struts2拦截器的工作原理。拦截器是基于AOP(面向切面编程)的概念,它位于...

    Struts2拦截器源码

    首先,理解拦截器的定义:拦截器是AOP(面向切面编程)的一个概念,在Struts2中,拦截器是基于Java的动态代理机制实现的。它们是一系列实现了`Interceptor`接口的类,可以在Action执行前后插入额外的行为。这些行为...

    struts2拦截器权限判断实例

    在“struts2拦截器权限判断实例”中,我们将创建一个自定义的拦截器来检查用户是否具有访问特定资源的权限。这个拦截器可能包括以下几个步骤: 1. **创建拦截器类**: 首先,我们需要创建一个实现了`Interceptor`...

    struts2拦截器实现拦截不文明字迹

    拦截器是Struts2框架的一个重要组成部分,能够帮助开发者实现一些在请求处理前后执行的通用逻辑,如日志记录、权限验证、数据校验等。在本场景中,我们将探讨如何使用Struts2拦截器来实现对不文明字迹或者敏感词汇的...

    Struts2学习案例(拦截器)

    在Struts2中,拦截器是基于Java的动态AOP(面向切面编程)实现的,它可以在Action调用前后插入额外的逻辑,比如日志记录、权限验证、事务管理等。拦截器通过配置文件或者注解与Action关联,形成一个拦截器栈,每个...

    struts2拦截器原理

    Struts2 拦截器是基于Java的Servlet Filter设计模式的一种实现,它提供了一种在Action执行前后插入额外逻辑的方式。拦截器是Struts2框架的核心组件之一,用于增强应用的功能,比如权限验证、日志记录、数据校验等。 ...

    STRUTS2拦截器控制页面访问权限的设计与实现

    STRUTS2拦截器控制页面访问权限的设计与实现,解决基于STRUTS2的web应用的程序访问控制,防止非法访问

    struts2拦截器权限设置

    ### Struts2拦截器权限设置 #### 背景与目的 在开发Web应用程序时,权限控制是一项重要的功能。它确保只有经过验证的用户才能访问特定的资源或执行某些操作。Struts2作为一款流行的Java Web框架,提供了丰富的功能...

    Struts2 拦截器 和 Java 中的动态代理

    总结来说,Struts2拦截器是实现业务逻辑增强和控制流程的重要组件,它基于Java的动态代理机制。通过在Action执行前后插入自定义代码,拦截器使得我们可以方便地进行如日志记录、权限验证等操作,而无需直接修改...

Global site tag (gtag.js) - Google Analytics