SSH系列:(20)权限过滤器

在系统中,① 需要验证用户的登录,只有登录后才能访问系统的资源。② 对于各个子系统,只有角色拥有“该子系统的权限”才可以操作。

编写LoginFilter过滤器,在过滤器中对用户访问的url进行登录验证,在登录的前提下再次验证如果访问的是纳税服务命名空间下的资源则利用权限验证接口PermissionCheck校验用户是否有“纳税服务”。

基本步骤:

(1)编写过滤器

(2)注册过滤器

(3)权限验证类

1、编写过滤器

LoginFilter.java

package com.rk.core.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.rk.core.constant.ProjectStatics;
import com.rk.core.permission.PermissionCheck;
import com.rk.tax.entity.User;

public class LoginFilter implements Filter {

	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,FilterChain chain) throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		HttpSession session = request.getSession();
		//判断当前请求地址是否是登录的请求地址
		String uri = request.getRequestURI();
		// TODO uri.length>0判断,验证它的价值
		if(!uri.contains("sys/login_")){
			//非登录请求
			if(session.getAttribute(ProjectStatics.USER) != null){
				//说明已经登录过
				//判断是否拥有访问纳税服务系统的权限
				if(uri.contains("/tax/")){
					//访问纳税服务子系统
					User user = (User) session.getAttribute(ProjectStatics.USER);
					//获取Spring容器
					WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
					PermissionCheck pc = (PermissionCheck)applicationContext.getBean("permissionCheck");
					if(pc.isAccessible(user,"nsfw")){
						//说明有权限,放行
						chain.doFilter(request, response);
					}
					else{
						//没有权限,跳转到没有权限提示页面
						response.sendRedirect(request.getContextPath() + "/sys/login_toNoPermissionUI.action");
					}
				}
				else{
					//非访问纳税服务子系统,则直接旅行
					chain.doFilter(request, response);
				}
			}
			else{
				//没有登录,跳转到登录页面
				response.sendRedirect(request.getContextPath() + "/sys/login_toLoginUI.action");
			}
		}
		else{
			//登录请求,直接放行
			chain.doFilter(request, response);
		}
	}

	public void init(FilterConfig arg0) throws ServletException {

	}

	public void destroy() {

	}
}

其中,关注这3个类:ProjectStaticsWebApplicationContextUtilsPermissionCheck

//访问纳税服务子系统
User user = (User) session.getAttribute(ProjectStatics.USER);
//获取Spring容器
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
PermissionCheck pc = (PermissionCheck)applicationContext.getBean("permissionCheck");

ProjectStatics.java

package com.rk.core.constant;

public class ProjectStatics {
	public static String USER = "SYS_USER"; 
}

PermissionCheck会在“3、权限验证”说明

WebApplicationContextUtils在“4、知识扩展”中说明

2、注册过滤器

在web.xml中注册LoginFilter过滤器。注意:应该放置在struts filter的前面。

  <filter>
  	<filter-name>loginFilter</filter-name>
  	<filter-class>com.rk.core.filter.LoginFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>loginFilter</filter-name>
  	<url-pattern>*.action</url-pattern>
  </filter-mapping>

完整的web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <filter>
  	<filter-name>loginFilter</filter-name>
  	<filter-class>com.rk.core.filter.LoginFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>loginFilter</filter-name>
  	<url-pattern>*.action</url-pattern>
  </filter-mapping>
  
  <filter>
    <filter-name>struts</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>struts</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>
  <display-name>OA System</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

3、权限验证

(1)PermissionCheck.java

package com.rk.core.permission;

import com.rk.tax.entity.User;

public interface PermissionCheck {
	/**
	 * 判断用户是否有code对应的权限
	 * @param user 用户
	 * @param code 子系统权限标识符
	 * @return true or false
	 */
	public boolean isAccessible(User user,String code);
}

(2)PermissionCheckImpl.java

package com.rk.core.permission.impl;

import java.util.List;

import javax.annotation.Resource;

import com.rk.core.permission.PermissionCheck;
import com.rk.tax.entity.Role;
import com.rk.tax.entity.RolePrivilege;
import com.rk.tax.entity.User;
import com.rk.tax.entity.UserRole;
import com.rk.tax.service.UserService;

public class PermissionCheckImpl implements PermissionCheck {
	@Resource
	private UserService userService;

	public boolean isAccessible(User user, String code) {
		//1、获取用户的所有角色
		List<UserRole> list = user.getUserRoles();
		if(list == null){
			list = userService.findUserRolesByUserId(user.getId());
			user.setUserRoles(list);
		}

		//2、根据每个角色对应的所有权限进行对比
		if(list != null && list.size()>0){
			for(UserRole ur : list){
				Role role = ur.getId().getRole();
				for(RolePrivilege rp : role.getRolePrivileges()){
					//进行对比 ,判断是否有code对应的权限
					if(code.equals(rp.getId().getCode())){
						//说明有权限,返回true
						return true;
					}
				}
			}
		}
		return false;
	}

}

(3)注册PermissionCheck到Spring的IOC容器中

bean-core.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
     	http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 获取主键属性的反射工具类 -->
	<bean id="hibernateConfigurationUtils" class="com.rk.core.utils.HibernateConfigurationUtils"></bean>
	<!-- 权限鉴定类 -->
	<bean id="permissionCheck" class="com.rk.core.permission.impl.PermissionCheckImpl"></bean>
</beans>

注意:最后要将bean-core.xml添加到applicationContext.xml文件中。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
     	http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

	<import resource="classpath:bean-base.xml"/>
	<import resource="classpath:com/rk/*/config/bean-*.xml"/>

</beans>

问题:为什么要将PermissionCheck注册到Spring的IOC容器内呢

解答:在PermissionCheckImpl类中,使用到了UserService,而UserService是由Spring的IOC容器管理的;如果想让Spring容器能够对PermissionCheckImpl类的userService变量进行注入,就必须要将PermissionCheckImpl类放置到Spring的IOC容器中,否则无法完成注入。

试想一下,如果在PermissionCheckImpl类中,使用userService = new UserServiceImpl();来完成,那么就会产生另外的问题:在UserServiceImpl类中,又使用到了userDao,而userDao又是需要通过Spring的IOC容器注入的;如果我们再继续通过userDao = new UserDaoImpl();来代替,那么实际上就多了一套重复的代码(UserServiceImpl.java、UserDaoImpl.java)。

4、知识扩展

4.1、WebApplicationContextUtils类

WebApplicationContextUtils类位于org.springframework.web.context.support包。它的作用是获取ServletContext下的WebApplicationContext的工具类。

Convenience methods for retrieving the root org.springframework.web.context.WebApplicationContext for a given ServletContext

在WebApplicationContextUtils下有两个方法

public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc)
public static WebApplicationContext getWebApplicationContext(ServletContext sc)

这两者的区别是:前者获取失败时,抛出异常;后者获取失败,则返回null。

源码:

package org.springframework.web.context.support;
public abstract class WebApplicationContextUtils { 

	/**
	 * Find the root WebApplicationContext for this web application, which is
	 * typically loaded via {@link org.springframework.web.context.ContextLoaderListener}.
	 * 
	 * @param sc ServletContext to find the web application context for
	 * @return the root WebApplicationContext for this web app
	 * @throws IllegalStateException if the root WebApplicationContext could not be found
	 * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
	 */
	public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc)
			throws IllegalStateException {

		WebApplicationContext wac = getWebApplicationContext(sc);
		if (wac == null) {
			throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
		}
		return wac;
	}

	/**
	 * Find the root WebApplicationContext for this web application, which is
	 * typically loaded via {@link org.springframework.web.context.ContextLoaderListener}.
	 * 
	 * @param sc ServletContext to find the web application context for
	 * @return the root WebApplicationContext for this web app, or {@code null} if none
	 * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
	 */
	public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
		return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
	}

	/**
	 * Find a custom WebApplicationContext for this web application.
	 * 
	 * @param sc ServletContext to find the web application context for
	 * @param attrName the name of the ServletContext attribute to look for
	 * @return the desired WebApplicationContext for this web app, or {@code null} if none
	 */
	public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
		Object attr = sc.getAttribute(attrName);
		if (attr == null) {
			return null;
		}
		if (attr instanceof RuntimeException) {
			throw (RuntimeException) attr;
		}
		if (attr instanceof Error) {
			throw (Error) attr;
		}
		if (attr instanceof Exception) {
			throw new IllegalStateException((Exception) attr);
		}
		if (!(attr instanceof WebApplicationContext)) {
			throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
		}
		return (WebApplicationContext) attr;
	}
}

4.2、WebApplicationContext接口

WebApplicationContext接口,也是位于org.springframework.web.context包下。


Interface to provide configuration for a web application. This is read-only
while the application is running, but may be reloaded if the implementation
supports this.

Like generic application contexts, web application contexts are hierarchical.
There is a single root context per application, while each servlet in the
application (including a dispatcher servlet in the MVC framework) has its own
child context.

源码:

package org.springframework.web.context;

import javax.servlet.ServletContext;

import org.springframework.context.ApplicationContext;

public interface WebApplicationContext extends ApplicationContext {
	/**
	 * Context attribute to bind root WebApplicationContext to on successful startup.
	 * <p>Note: If the startup of the root context fails, this attribute can contain
	 * an exception or error as value. Use WebApplicationContextUtils for convenient
	 * lookup of the root WebApplicationContext.
	 * @see org.springframework.web.context.support.WebApplicationContextUtils#getWebApplicationContext
	 * @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext
	 */
	String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

	/**
	 * Scope identifier for request scope: "request".
	 * Supported in addition to the standard scopes "singleton" and "prototype".
	 */
	String SCOPE_REQUEST = "request";

	/**
	 * Scope identifier for session scope: "session".
	 * Supported in addition to the standard scopes "singleton" and "prototype".
	 */
	String SCOPE_SESSION = "session";

	/**
	 * Scope identifier for global session scope: "globalSession".
	 * Supported in addition to the standard scopes "singleton" and "prototype".
	 */
	String SCOPE_GLOBAL_SESSION = "globalSession";

	/**
	 * Scope identifier for the global web application scope: "application".
	 * Supported in addition to the standard scopes "singleton" and "prototype".
	 */
	String SCOPE_APPLICATION = "application";

	/**
	 * Name of the ServletContext environment bean in the factory.
	 * @see javax.servlet.ServletContext
	 */
	String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

	/**
	 * Return the standard Servlet API ServletContext for this application.
	 * <p>Also available for a Portlet application, in addition to the PortletContext.
	 */
	ServletContext getServletContext();
}
时间: 08-18

SSH系列:(20)权限过滤器的相关文章

[Android学习系列20]图形图像的一些事

参考: android图形系统详解一:Canvas android图形系统详解二:Drawables android图形系统详解三:形状Drawable和九宫格 android图形系统详解四:控制硬加速 android图形系统详解五:Android绘制模式 android图形系统详解六:View layer[Android学习系列20]图形图像的一些事,码迷,mamicode.com

【SSH系列】静态代理&amp;&amp;动态代理

从设计模式说起 代理模式是二十三中设计模式中的一种,代理模式就是指由一个代理主题来操作真实的主题,真实的主题执行具体的业务操作,而代理主题负责其她相关业务,简而言之,代理模式可以由以下三个部分组成: a.抽象角色:通过接口或抽象类声明真实角色实现的业务方法. b.代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作. c.真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用.第一次接触代理模式的是在学习大话设计模式的时候,首先

SSH系列:(16)角色-权限管理(后台)

1.角色和权限的关系 系统中可以存在多个角色,每个角色可以自由的组合系统定义的权限集合,即角色和权限的关系是多对多的关系.为了保存这种多对多关系,需要一个"角色权限表"来保存. 角色和权限的多对多关系,可以进行拆分:"角色"与"角色权限"的关系."权限"和"角色权限"的关系."角色"与"角色权限"的关系是一对多的关系:而"权限"与"角色权

SSH系列:(17)角色-权限管理(前台JSP)

1.listUI.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="/struts-tags" prefix="s" %> <html> <head>     <%@include file="/common/header.jsp"%&

SSH系列:(19)系统首页、子系统首页、登录页、项目主页

在这里,有三个名词需要区分:项目首页.系统首页.子系统首页.登录页. 项目首页是指在web.xml文件中配置的页面.   <welcome-file-list>     <welcome-file>index.jsp</welcome-file>   </welcome-file-list> 当一个系统比较大时,可能包含多个子系统.系统有自己的主页,称为系统首页:而子系统也有自己的主页,称为子系统首页. 登录页,则是用户进行登录的页面. 1.系统首页 (1)

[CentOS 7系列]特殊权限与链接模式

一.特殊权限 在linux系统中,有一些特殊的权限,它们适用于极少数特殊的场景.虽然适用的场景比较少,但不代表它们不重要.比如set_uid权限,这个权限的存在,才使得操作系统的用户才能自如的更改登录口令. 在linux操作系统中,特殊权限主要有以下几个: 1.set_uid 当普通用户执行带set_uid标识位的命令文件时,将临时使用所有者的权限执行该命令. [[email protected] ~]# ll /usr/bin/ls -rwxr-xr-x. 1 root root 117656

【转载】大型网站架构系列20本书

[转载]http://www.cnblogs.com/chy2055/p/5181352.html 学习是技术人员成长的基础,本次分享20本技术方面的书籍,这些书不是每一本都是经典,但是每一本都有其特点.以下20本大部分本人都看过,因此推荐给大家.(本次推荐的20本只是一个参考,比如像Head First,Java编程思想等经典书籍是大家都知道,因此不在推荐之列) 本次分享大纲 大型网站架构系列 分布式系统系列 BAT技术文学系列 架构设计系列 本次分享总结 一.大型网站架构系列 第一本:<大型

SSH系列:(28)JDK Timer和Quartz

常见的任务调度有Jdk 的Timer 以及 spring中quartz任务调度框架等. 1.JDK Timer 如果是执行简单的有一定执行周期的,那么使用jdk自带的timer是最简单的. 具体步骤: ①.编写一个简单类继承 TimerTask,在这个新编写的类中重写父类中run方法,在run中执行要执行的操作: ②.编写一个简单类,在类中写一个方法,方法体中使用timer调用在①中创建的类并设置好timer执行周期. MyTask.java package com.rk.test; impor

springMVC笔记系列(7)——HiddenHttpMethodFilter过滤器

什么是REST?首先来段介绍吧. REST: 即 Representational State Transfer. (资源)表现层状态转化. 是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解. 扩展方便,所以正得到越来越多网站的采用. 资源(Resources) : 网络上的一个实体,或者说是网络上的一个具体信息.它可以是一段文本.一张图片.一首歌曲.一种服务, 总之就是一个具体的存在.可以用一个URI(统一资源定位符)指向它, 每种资源对应一个特定的 URI . 要获取这个资源