Struts2拦截器实现细颗粒权限控制

以前做的电力系统,实现对用户的角色进行细颗粒度权限控制的设计,现在分享下:
先看数据表设计:

* 角色表:


* 用户角色中间表(多对多关系)


* 权限表:(这里使用ztree动态加载左侧菜单栏,只显示用户所具有的权限的菜单栏项。)


* 角色和权限中间表:



通过上面表结构,大家应该大概了解用户,角色,权限的大概关系。现在开始进行Struts2拦截器实现细颗粒权限控制

(1) util包下创建注解的类AnnotationLimit,用来控制在Action类中的方法。例如:在Action的方法上定义:@AnnotationLimit(mid="an",pid="am")

/**
 * 自定义注解
 */
//被这个注解修饰的注解,利用反射,将其他的注解读取出来
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationLimit {
String mid();  //子模块模块名称
String pid(); //父模块操作名称
}

(2) util包下创建拦截器ErrorAndLimitInterceptor,代码如下:

@SuppressWarnings("serial")
public class ErrorAndLimitInterceptor extends MethodFilterInterceptor {

	public void init() {

	}

	/**
	 * 过滤器过滤url(.do和.jsp)
	 * 拦截器拦截url(.do)
	 *   actioninvocation.invoke():调用struts2的Action的方法,并返回String类型的对应的返回值
	 */
	public String doIntercept(ActionInvocation actioninvocation) {
		//把自定义错误信息 放置到request中
		HttpServletRequest request = (HttpServletRequest) actioninvocation
						.getInvocationContext().get(StrutsStatics.HTTP_REQUEST);
		try {
			//获取请求的action对象
			Object action = actioninvocation.getAction();
			//获取请求的方法的名称
			String methodName = actioninvocation.getProxy().getMethod();
			//获取action中的方法的封装类(action中的方法没有参数)
			Method method = action.getClass().getMethod(methodName, null);
			
			String result = null; // Action的返回值   
			//在完成跳转Action之前完成细颗粒权限控制,控制Action的每个方法
			//检查注解,是否可以操作权限的URL
			boolean flag = isCheckLimit(request,method);
			if(flag){
				// 运行被拦截的Action,期间如果发生异常会被catch住   
				result = actioninvocation.invoke();
			}
			else{
				request.setAttribute("errorMsg", "对不起!您没有权限操作此功能!");
				return "errorMsg";
			}
			return result;
		} catch (Exception e) {
			/**  
			 * 处理异常  
			 */
			String errorMsg = "出现错误信息,请查看日志!";
			//通过instanceof判断到底是什么异常类型   
			if (e instanceof RuntimeException) {
				//未知的运行时异常   
				RuntimeException re = (RuntimeException) e;
				//re.printStackTrace();
				errorMsg = re.getMessage().trim();
			}
			/**  
			 * 发送错误消息到页面  
			 */
			request.setAttribute("errorMsg", errorMsg);

			/**  
			 * log4j记录日志  
			 */
			Log log = LogFactory
					.getLog(actioninvocation.getAction().getClass());
			log.error(errorMsg, e);
			return "errorMsg";
		}// ...end of catch   
	}

	public void destroy() {

	}
	
	/**验证细颗粒权限控制*/
	public boolean isCheckLimit(HttpServletRequest request, Method method) {
		if(method == null){
			return false;
		}
		//获取当前的登陆用户
		ElecUser elecUser = (ElecUser)request.getSession().getAttribute("globle_user");
		if(elecUser == null){
			return false;
		}
		
		//获取当前登陆用户的角色(一个用户可以对应多个角色)
		Hashtable<String, String> ht = (Hashtable)request.getSession().getAttribute("globle_role");
		if(ht == null){
			return false;
		}
		//处理注解,判断方法上是否存在注解(注解的名称为:AnnotationLimit)
		/*
		 * 例如:
		 * 	@AnnotationLimit(mid="aa",pid="0")
	        public String home(){
		 */
		boolean isAnnotationPresent = method.isAnnotationPresent(AnnotationLimit.class);
		
		//不存在注解(此时不能操作该方法)
		if(!isAnnotationPresent){
			return false;
		}
		
		//存在注解(调用注解)
		AnnotationLimit limit = method.getAnnotation(AnnotationLimit.class);
		
		//获取注解上的值
		String mid = limit.mid();  //权限子模块名称
		String pid = limit.pid();  //权限父操作名称
		
		/**
		 * 如果登陆用户的角色id+注解上的@AnnotationLimit(mid="aa",pid="0")
		 *   * 在elec_role_popedom表中存在   flag=true,此时可以访问Action的方法;
		 *   * 在elec_role_popedom表中不存在 flag=false,此时不能访问Action的方法;
		 */
		boolean flag = false;
		//拦截器中加载spring容器,从而获取Service类,使用Service类查询对应的用户信息
		WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
		IElecRoleService elecRoleService = (IElecRoleService)wac.getBean(IElecRoleService.SERVICE_NAME);
		//遍历角色ID
		if(ht!=null && ht.size()>0){
			for(Iterator<Entry<String, String>> ite = ht.entrySet().iterator();ite.hasNext();){
				Entry<String, String> entry = ite.next();
				//获取角色ID
				String roleID = entry.getKey();
				flag = elecRoleService.findRolePopedomByID(roleID, mid, pid);
				if(flag){
					break;
				}
			}
		}
		return flag;
	}
}

(3) ElecRoleService类下(即角色模块service)创建新增方法,使用角色ID,权限code,父级权限code作为联合主键查询角色权限表,判断当前用户是否可以访问该操作。 

  /**使用角色ID,子权限编号,父权限编号,查询角色权限表的所有数据*/
	public boolean findRolePopedomByID(String roleID,String mid,String pid) {
		//组织查询条件
		String condition = "";
		List<Object> paramsList = new ArrayList<Object>();
		//角色ID
		if(StringUtils.isNotBlank(roleID)){
			condition += " and o.roleID = ?";
			paramsList.add(roleID);
		}
		//子权限名称
		if(StringUtils.isNotBlank(mid)){
			condition += " and o.mid = ?";
			paramsList.add(mid);
		}
		//父权限名称
		if(StringUtils.isNotBlank(pid)){
			condition += " and o.pid = ?";
			paramsList.add(pid);
		}
		Object [] params = paramsList.toArray();
		//查询对应的角色权限信息
		List<ElecRolePopedom> list = elecRolePopedomDao.findCollectionByConditionNoPage(condition, params, null);
		boolean flag = false;
		if(list!=null && list.size()>0){
			flag = true;
		}
		return flag;
	}

(4) struts.xml中定义自定义拦截器:放置在package

<interceptors>
		   <!-- 声明拦截器 -->
		   <interceptor name="errorAndLimitInterceptor" class="cn.best.elec.util.ErrorAndLimitInterceptor" />
		   <!-- 配置拦截器栈 -->
		   <interceptor-stack name="myErrorAndLimitInterceptor">
		        <interceptor-ref name="defaultStack" />
		   		<interceptor-ref name="errorAndLimitInterceptor">
		   			<!-- 配置哪些方法不被拦截器 -->
		   			<param name="excludeMethods">menuHome,title,left,change,loading,logout,alermStation,alermDevice,showMenu</param>
		   		</interceptor-ref>
		   </interceptor-stack>
		</interceptors>
		<!-- 覆盖底层的拦截器栈 对包中的所有action都有效 -->
		<default-interceptor-ref name="myErrorAndLimitInterceptor"/>
		<!-- 全局返回 -->
		<global-results>
			<result name="close">/close.jsp</result>
			<result name="errorMsg">/errorMsg.jsp</result>
		</global-results>
		<global-exception-mappings>
			<exception-mapping result="errorMsg" exception="java.lang.Exception"></exception-mapping>
		</global-exception-mappings>

(5) 在Action的方法上定义:

  @AnnotationLimit(mid="an",pid="am")
	public String home(){
    	    
  }

大功告成。








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值