在系统中,① 需要验证用户的登录,只有登录后才能访问系统的资源。② 对于各个子系统,只有角色拥有“该子系统的权限”才可以操作。
编写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个类:ProjectStatics、WebApplicationContextUtils、PermissionCheck。
//访问纳税服务子系统
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();
}原文:http://lsieun.blog.51cto.com/9210464/1840694