准备:
1、Spring Security需要自定义一个继承至AbstractSecurityInterceptor的Filter,该抽象类包含了AccessDecisionManager(决策管理器)、AuthenticationManager(身份认证管理器)的setter, 可以通过Spring自动注入,另外,资源角色授权器需要单独自定义注入
2、AccessDecisionManager(决策管理器)的实现需要实现AccessDecisionManager接口,在实现的decide(Authentication arg0, Object arg1,Collection<ConfigAttribute> arg2)方法中,需要将用户具有的角色权限Collection<GrantedAuthority> grantedAuthorities=arg0.getAuthorities();与访问该资源所需要的金额角色权限Collection<ConfigAttribute> arg2进行比较,若有一个角色匹配,则放行允许该用户访问此资源。
3、AuthenticationManager(身份认证管理器)可以通过applicationContext-security.xml中<authentication-manager />标签实现。该标签需要引用一个实现了UserDetailService接口的类。该类的loadUserByUsername(String username)方法,通过传进来的用户名返回一个User对象,构造该User对象时需要传入GrantedAuthority的Collection,此时可以通过不同的用户名赋予不同的GrantedAuthority。
4、资源角色授权器需要实现FilterInvocationSecurityMetadataSource接口。请求的资源所需要的角色权限在服务器启动时候就已经确定的,所以在该实现类的构造方法中需要确定每一种资源需要那些角色权限,通过一个Map<String, List<ConfigAttribute>>即可将所有资源所需要的List<ConfigAttribute>存储起来。该实现类中getAttributes(Object arg0)方法,可以通过请求的url返回对应的Collection<ConfigAttribute>,通过传进来的FilterInvocation可以得到RequestUrl,然后遍历Map<String, List<ConfigAttribute>>。
一、定义继承至AbstractSecurityInterceptor的CustomSecurityFilter。
1 package com.spring.security.demo; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 12 import org.springframework.security.access.SecurityMetadataSource; 13 import org.springframework.security.access.intercept.AbstractSecurityInterceptor; 14 import org.springframework.security.access.intercept.InterceptorStatusToken; 15 import org.springframework.security.web.FilterInvocation; 16 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 17 18 public class CustomSecurityFilter extends AbstractSecurityInterceptor implements 19 Filter 20 { 21 private FilterInvocationSecurityMetadataSource securityMetadataSource; 22 23 public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() 24 { 25 return securityMetadataSource; 26 } 27 28 public void setSecurityMetadataSource( 29 FilterInvocationSecurityMetadataSource securityMetadataSource) 30 { 31 this.securityMetadataSource = securityMetadataSource; 32 } 33 34 @Override 35 public void destroy() 36 { 37 // TODO Auto-generated method stub 38 39 } 40 41 @Override 42 public void doFilter(ServletRequest arg0, ServletResponse arg1, 43 FilterChain arg2) throws IOException, ServletException 44 { 45 FilterInvocation fileInvocation = new FilterInvocation(arg0, arg1, arg2); 46 InterceptorStatusToken interceptorStatusToken = this 47 .beforeInvocation(fileInvocation); 48 fileInvocation.getChain().doFilter(arg0, arg1); 49 this.afterInvocation(interceptorStatusToken, null); 50 } 51 52 @Override 53 public void init(FilterConfig arg0) throws ServletException 54 { 55 // TODO Auto-generated method stub 56 57 } 58 59 @Override 60 public Class<? extends Object> getSecureObjectClass() 61 { 62 return FilterInvocation.class; 63 } 64 65 @Override 66 public SecurityMetadataSource obtainSecurityMetadataSource() 67 { 68 return this.securityMetadataSource; 69 } 70 71 }
二、定义AccessDecisionManager(决策管理器)、AuthenticationManager(身份认证管理器)、实现了UserDetailService接口的CustomUserDetailService。
CustomAccessDecisionManager.java
1 package com.spring.security.demo.dependent.components; 2 3 import java.util.Collection; 4 import java.util.Iterator; 5 6 import org.springframework.security.access.AccessDecisionManager; 7 import org.springframework.security.access.AccessDeniedException; 8 import org.springframework.security.access.ConfigAttribute; 9 import org.springframework.security.access.SecurityConfig; 10 import org.springframework.security.authentication.InsufficientAuthenticationException; 11 import org.springframework.security.core.Authentication; 12 import org.springframework.security.core.GrantedAuthority; 13 14 public class CustomAccessDecisionManager implements AccessDecisionManager 15 { 16 /** 17 * Authentication arg0 --->用户具有的角色权限 18 * Collection<ConfigAttribute> arg2 --->访问该资源所需的角色权限 19 */ 20 @Override 21 public void decide(Authentication arg0, Object arg1, 22 Collection<ConfigAttribute> arg2) throws AccessDeniedException, 23 InsufficientAuthenticationException 24 { 25 Iterator<ConfigAttribute> iter = arg2.iterator(); 26 while (iter.hasNext()) 27 { 28 String accessResourceNeedRole = ((SecurityConfig) iter.next()) 29 .getAttribute(); 30 for (GrantedAuthority grantedAuthority : arg0.getAuthorities()) 31 { 32 String userOwnRole = grantedAuthority.getAuthority(); 33 if (accessResourceNeedRole.equals(userOwnRole)) 34 { 35 return; 36 } 37 } 38 } 39 throw new AccessDeniedException("访问被拒绝!"); 40 } 41 42 @Override 43 public boolean supports(ConfigAttribute arg0) 44 { 45 return true; 46 } 47 48 @Override 49 public boolean supports(Class<?> arg0) 50 { 51 return true; 52 } 53 54 }
CustomFilterInvocationSecurityMetadataSource.java
1 package com.spring.security.demo.dependent.components; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.HashMap; 6 import java.util.Iterator; 7 import java.util.List; 8 import java.util.Map; 9 10 import org.springframework.security.access.ConfigAttribute; 11 import org.springframework.security.access.SecurityConfig; 12 import org.springframework.security.web.FilterInvocation; 13 import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 14 import org.springframework.security.web.util.AntUrlPathMatcher; 15 import org.springframework.security.web.util.UrlMatcher; 16 17 public class CustomFilterInvocationSecurityMetadataSource implements 18 FilterInvocationSecurityMetadataSource 19 { 20 private Map<String, List<ConfigAttribute>> mp; 21 private UrlMatcher urlMatcher; 22 23 /** 24 * 构造每一种资源所需要的角色权限 25 */ 26 public CustomFilterInvocationSecurityMetadataSource() 27 { 28 super(); 29 this.mp = new HashMap<String, List<ConfigAttribute>>(); 30 this.urlMatcher = new AntUrlPathMatcher(); 31 List<ConfigAttribute> list = new ArrayList<ConfigAttribute>(); 32 ConfigAttribute cb = new SecurityConfig("Role_ADMIN"); // 构造一个权限(角色) 33 ConfigAttribute cbUser = new SecurityConfig("Role_USER"); // 构造一个权限(角色) 34 ConfigAttribute cbManager = new SecurityConfig("Role_MANAGER"); // 构造一个权限(角色) 35 list.add(cb); 36 list.add(cbUser); 37 list.add(cbManager); 38 39 mp.put("/Main.jsp", list); 40 list.remove(2); 41 mp.put("/Main2.jsp", list); 42 } 43 44 @Override 45 public Collection<ConfigAttribute> getAllConfigAttributes() 46 { 47 return null; 48 } 49 50 /** 51 * 获取访问某一个url所需的角色 52 */ 53 @Override 54 public Collection<ConfigAttribute> getAttributes(Object arg0) 55 throws IllegalArgumentException 56 { 57 String requestUrl = ((FilterInvocation) arg0).getRequestUrl(); 58 Iterator<String> iter = this.mp.keySet().iterator(); 59 while (iter.hasNext()) 60 { 61 String temp = iter.next(); 62 if (this.urlMatcher.pathMatchesUrl(requestUrl, temp)) 63 { 64 return mp.get(temp); 65 } 66 } 67 68 return null; 69 } 70 71 @Override 72 public boolean supports(Class<?> arg0) 73 { 74 return true; 75 } 76 77 }
CustomUserDetailService.java
1 package com.spring.security.demo.dependent.components; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.springframework.dao.DataAccessException; 7 import org.springframework.security.core.GrantedAuthority; 8 import org.springframework.security.core.authority.GrantedAuthorityImpl; 9 import org.springframework.security.core.userdetails.User; 10 import org.springframework.security.core.userdetails.UserDetails; 11 import org.springframework.security.core.userdetails.UserDetailsService; 12 import org.springframework.security.core.userdetails.UsernameNotFoundException; 13 14 public class CustomUserDetailService implements UserDetailsService 15 { 16 /** 17 * arg0 --->登录的用户名 18 */ 19 @Override 20 public UserDetails loadUserByUsername(String arg0) 21 throws UsernameNotFoundException, DataAccessException 22 { 23 List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(); 24 GrantedAuthority grantedAuthority = null; 25 26 if ("admin".equals(arg0)) 27 { 28 grantedAuthority = new GrantedAuthorityImpl("Role_ADMIN"); 29 } 30 else if ("manager".equals(arg0)) 31 { 32 grantedAuthority = new GrantedAuthorityImpl("Role_MANAGER"); 33 } 34 else 35 { 36 grantedAuthority = new GrantedAuthorityImpl("Role_USER"); 37 } 38 grantedAuthorities.add(grantedAuthority); 39 40 User user = new User(arg0, "123456", true, true, true, true, 41 grantedAuthorities); 42 43 return user; 44 } 45 46 }
三、完成applicationContext-security.xml以及web.xml的配置
applicationContext-security.xml
1 <beans:beans xmlns="http://www.springframework.org/schema/security" 2 xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 4 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"> 5 6 <!-- 用户验证通过才能授权,若不通过会跳到authentication-failure-url(验证失败页面) 7 若用户验证通过,但没有default-target-url的访问权限,则会跳转至access-denied-page(授权失败页面) --> 8 <http access-denied-page="/AccessDenied.jsp"> 9 <intercept-url pattern="/Login.jsp" filters="none" /> 10 <logout logout-success-url="/Login.jsp" /> 11 <form-login login-page="/Login.jsp" default-target-url="/Main.jsp" 12 authentication-failure-url="/Login.jsp" /> 13 <http-basic /> 14 15 <custom-filter ref="CustomSecurityFilter" before="FILTER_SECURITY_INTERCEPTOR" /> 16 </http> 17 18 <beans:bean id="CustomSecurityFilter" 19 class="com.spring.security.demo.CustomSecurityFilter"> 20 21 <!-- 注入决策管理器 --> 22 <beans:property name="accessDecisionManager" ref="CC_AccessDecisionManager"></beans:property> 23 24 <!-- 注入资源角色授权管理器 --> 25 <beans:property name="securityMetadataSource" ref="CC_SecurityMetadataSource"></beans:property> 26 27 <!-- 注入身份认证管理器 --> 28 <beans:property name="authenticationManager" ref="CC_AuthenticationManager"></beans:property> 29 30 </beans:bean> 31 32 <beans:bean id="CC_SecurityMetadataSource" 33 class="com.spring.security.demo.dependent.components.CustomFilterInvocationSecurityMetadataSource"></beans:bean> 34 35 <beans:bean id="CC_AccessDecisionManager" 36 class="com.spring.security.demo.dependent.components.CustomAccessDecisionManager"></beans:bean> 37 38 <authentication-manager alias="CC_AuthenticationManager"> 39 <authentication-provider user-service-ref="AidUserDetailService"></authentication-provider> 40 </authentication-manager> 41 42 <beans:bean id="AidUserDetailService" 43 class="com.spring.security.demo.dependent.components.CustomUserDetailService"></beans:bean> 44 </beans:beans>
web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 5 version="3.0"> 6 <listener> 7 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 8 </listener> 9 10 <context-param> 11 <param-name>contextConfigLocation</param-name> 12 <param-value>/WEB-INF/applicationContext*.xml</param-value> 13 </context-param> 14 15 <filter> 16 <filter-name>springSecurityFilterChain</filter-name> 17 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 18 </filter> 19 20 <filter-mapping> 21 <filter-name>springSecurityFilterChain</filter-name> 22 <url-pattern>/*</url-pattern> 23 </filter-mapping> 24 25 <display-name></display-name> 26 <welcome-file-list> 27 <welcome-file>index.jsp</welcome-file> 28 </welcome-file-list> 29 </web-app>
四、完成前台测试页面
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>用户登录</title> 13 14 <meta http-equiv="pragma" content="no-cache"> 15 <meta http-equiv="cache-control" content="no-cache"> 16 <meta http-equiv="expires" content="0"> 17 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 18 <meta http-equiv="description" content="This is my page"> 19 <!-- 20 <link rel="stylesheet" type="text/css" href="styles.css"> 21 --> 22 23 </head> 24 25 <body> 26 <div> 27 用户名:admin (admin拥有Role_ADMIN角色,其他任意用户拥有Role_USER角色) 28 密码:123456 29 </div> 30 <hr /> 31 <form action="j_spring_security_check" method="POST"> 32 用户名:<input type="text" name="j_username" /><br /> 33 密码:<input type="password" name="j_password"><br /> 34 <input type="submit" value="登录"> 35 </form> 36 </body> 37 </html>