Spring Security资源配置入门讲解

时间:2022-09-17 20:32:24


这是我使用的表结构

表名:RESOURCE 解释:资源表
备注: 资源表

RESOURCE(资源表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

ID

id

INT(11)

11

TYPE

类型(URL,METHOD)

VARCHAR(50)

50

VALUE

URL

VARCHAR(50)

50

MODEL_NAME

模块名

VARCHAR(50)

50

PARENT_ID

父模块ID

VARCHAR(50)

50

 


表名:ROLE 解释:角色表
备注: 角色表

ROLE(角色表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

ID

id

INT(11)

11

NAME

角色名

VARCHAR(50)

50

DESCRIPTION

角色描述

VARCHAR(50)

50

 


表名:ROLE_RESOURCE 解释:角色资源表
备注: 角色资源表

ROLE_RESOURCE(角色资源表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

ROLE_ID

角色ID

VARCHAR(50)

50

RESOURCE_ID

资源ID

VARCHAR(50)

50

 


表名:USER 解释:用户表
备注: 用户表

USER(用户表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

NAME

用户名

VARCHAR(50)

50

PASSWORD

密码

VARCHAR(50)

50

DISABLED

是否有效

CHAR(1)

1

EMAIL

邮箱

VARCHAR(100)

100

 


表名:USER_ROLE 解释:用户角色表
备注: 用户角色表

USER_ROLE(用户角色表)

是否主键

字段名

字段描述

数据类型

长度

可空

约束

缺省值

备注

USER_ID

用户ID

VARCHAR(50)

50

ROLE_ID

角色ID

VARCHAR(50)

50

 

相关的jar包可到spring官网下载,我使用的是spring security 3.1.3

下载链接:

http://repo.springsource.org/libs-release-local/org/springframework/security/spring-security/3.1.3.RELEASE/spring-security-3.1.3.RELEASE-dist.zip

 

首先web.xml配置

 

 

[html] view plaincopy
  1. <context-param>  
  2.         <param-name>contextConfigLocation</param-name>  
  3.         <param-value>  
  4.             classpath:/config/*.xml   
  5.         </param-value>  
  6.     </context-param>  
  7.     <!-- spring监听 -->  
  8.     <listener>  
  9.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  10.     </listener>  
  11.     <!-- Spring Security会话控制 -->  
  12.     <listener>  
  13.         <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>  
  14.     </listener>  
  15. <!-- Spring security Filter -->  
  16.     <filter>  
  17.         <filter-name>springSecurityFilterChain</filter-name>  
  18.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  19.     </filter>  
  20.     <filter-mapping>  
  21.         <filter-name>springSecurityFilterChain</filter-name>  
  22.         <url-pattern>/*</url-pattern>  
  23.     </filter-mapping>  


这里主要做了三件事,

1、加载Spring;

2、加载Spring Security;

3、添加Spring Security Session监听器(用于控制登录)

 

Spring Secirty如下:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans:beans xmlns="http://www.springframework.org/schema/security"  
  3.     xmlns:beans="http://www.springframework.org/schema/beans"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  6.                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">  
  7.       
  8.     <debug/>  
  9.       
  10.     <global-method-security  pre-post-annotations="enabled" />  
  11.       
  12.     <!-- 此目录下不需要过滤 -->  
  13.     <http pattern="/js/**" security="none"/>  
  14.     <http pattern="/resources/**" security="none"/>  
  15.     <http pattern="/css/**" security="none"/>  
  16.     <http pattern="/dwr/**" security="none"/>  
  17.     <http pattern="/images/**" security="none"/>  
  18.     <http pattern="/login.jsp" security="none"/>  
  19.       
  20.       
  21.       
  22.     <http use-expressions="true">  
  23.         <!-- 非匿名用户就允许访问 -->  
  24.         <intercept-url pattern="/index.jsp" access="isAuthenticated()"/>  
  25.         <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true"  always-use-default-target="true" default-target-url="/index.jsp" />  
  26.         <logout logout-success-url="/login.jsp"/>  
  27.         <!-- 没有权限访问的页面 -->  
  28.         <access-denied-handler error-page="/403.jsp"/>  
  29.         <session-management></session-management>  
  30.         <remember-me/>  
  31.         <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>  
  32.     </http>  
  33.       
  34.       
  35.       
  36.     <!-- 指定提示信息 -->  
  37.     <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
  38.         <beans:property name="basename" value="classpath:spring-security"></beans:property>  
  39.     </beans:bean>  
  40.       
  41.       
  42.     <authentication-manager alias="myAuthenticationManager">  
  43.         <authentication-provider ref="authenticationProvider">  
  44.         </authentication-provider>  
  45.     </authentication-manager>  
  46.       
  47.     <beans:bean id="authenticationProvider"   
  48.         class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">  
  49.             <beans:property name="userDetailsService" ref="userdetailService" />  
  50.             <!--显示用户错误信息-->  
  51.             <beans:property name="hideUserNotFoundExceptions" value="false" />  
  52.             <beans:property  name="passwordEncoder" ref="md5password"></beans:property >  
  53.     </beans:bean>  
  54.     <!-- 密码加密策略 -->  
  55.     <beans:bean name="md5password" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"></beans:bean>  
  56.       
  57.     <beans:bean name="userdetailService" class="com.yindejin.system.MyAuthenticationManager">  
  58.         <beans:property name="systemService" ref="systemService"></beans:property>  
  59.     </beans:bean>  
  60.       
  61.     <beans:bean name="myFilter" class="com.yindejin.system.MySecurityFilter">  
  62.         <!-- 用户拥有的权限 -->    
  63.         <beans:property name="authenticationManager" ref="myAuthenticationManager" />    
  64.         <!-- 用户是否拥有所请求资源的权限 -->    
  65.         <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />    
  66.         <!-- 资源与权限对应关系 -->    
  67.         <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />  
  68.     </beans:bean>  
  69.       
  70.       
  71.       
  72.        
  73.     <beans:bean id="myAccessDecisionManager" class="com.yindejin.system.MyAccessDecisionManager"></beans:bean>    
  74.     <beans:bean id="mySecurityMetadataSource" class="com.yindejin.system.MySecurityMetadataSource">    
  75.         <beans:constructor-arg name="systemService" ref="systemService"></beans:constructor-arg>    
  76.     </beans:bean>    
  77.       
  78.       
  79.   
  80. </beans:beans>  

<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>

这里的FILTER_SECURITY_INTERCEPTOR是Spring Security过滤器链中默认的Filter,

他的主要功能是

1、校验用户名、密码;

2、初始化时一次性加载所有的资源角色信息

3、检查用户访问权限

我们自定义的Filter必须在它之前,由于我们自己的过滤器和默认过滤器功能是一样的,所以就替换掉了原来的过滤器。

接下来是myFilter几个关键类


 

 


MySecurityFilter

[java] view plaincopy
  1. package com.yindejin.system;  
  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 MySecurityFilter extends AbstractSecurityInterceptor implements Filter {  
  19.     //与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,  
  20.     //其他的两个组件,已经在AbstractSecurityInterceptor定义  
  21.     private FilterInvocationSecurityMetadataSource securityMetadataSource;  
  22.   
  23.     @Override  
  24.     public SecurityMetadataSource obtainSecurityMetadataSource() {  
  25.         return this.securityMetadataSource;  
  26.     }  
  27.   
  28.     public void doFilter(ServletRequest request, ServletResponse response,  
  29.             FilterChain chain) throws IOException, ServletException {  
  30.         FilterInvocation fi = new FilterInvocation(request, response, chain);  
  31.         invoke(fi);  
  32.     }  
  33.       
  34.     private void invoke(FilterInvocation fi) throws IOException, ServletException {  
  35.         System.out.println("用户发送请求! ");  
  36.         InterceptorStatusToken token = null;  
  37.         token = super.beforeInvocation(fi);  
  38.         try {  
  39.             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
  40.         } finally {  
  41.             super.afterInvocation(token, null);  
  42.         }  
  43.     }  
  44.   
  45.     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {  
  46.         return securityMetadataSource;  
  47.     }  
  48.   
  49.     public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {  
  50.         this.securityMetadataSource = securityMetadataSource;  
  51.     }  
  52.       
  53.     public void init(FilterConfig arg0) throws ServletException {  
  54.         // TODO Auto-generated method stub  
  55.     }  
  56.       
  57.     public void destroy() {  
  58.         // TODO Auto-generated method stub  
  59.           
  60.     }  
  61.   
  62.     @Override  
  63.     public Class<? extends Object> getSecureObjectClass() {  
  64.         //下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误  
  65.         return FilterInvocation.class;  
  66.     }}  


 

MySecurityMetadataSource

[java] view plaincopy
  1. package com.yindejin.system;  
  2.   
  3.   
  4. import java.util.ArrayList;  
  5. import java.util.Collection;  
  6. import java.util.HashMap;  
  7. import java.util.LinkedHashMap;  
  8. import java.util.List;  
  9. import java.util.Map;  
  10. import java.util.Set;  
  11.   
  12. import javax.servlet.http.HttpServletRequest;  
  13.   
  14. import org.springframework.security.access.ConfigAttribute;  
  15. import org.springframework.security.access.SecurityConfig;  
  16. import org.springframework.security.web.FilterInvocation;  
  17. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
  18. import org.springframework.security.web.util.AntPathRequestMatcher;  
  19. import org.springframework.security.web.util.RequestMatcher;  
  20.   
  21. import com.yindejin.system.service.ISystemService;  
  22. import com.yindejin.vo.Resource;  
  23. import com.yindejin.vo.Role;  
  24. import com.yindejin.vo.User;  
  25.   
  26. //1 加载资源与权限的对应关系  
  27. public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {  
  28.     //由spring调用  
  29.     public MySecurityMetadataSource(ISystemService systemService) {  
  30.         this.systemService = systemService;  
  31.     }  
  32.   
  33.     private ISystemService systemService;  
  34.     public ISystemService getSystemService() {  
  35.         return systemService;  
  36.     }  
  37.   
  38.     public void setSystemService(ISystemService systemService) {  
  39.         this.systemService = systemService;  
  40.     }  
  41.   
  42.     private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> resourceMap = null;  
  43.       
  44.   
  45.   
  46.     public Collection<ConfigAttribute> getAllConfigAttributes() {  
  47.         // TODO Auto-generated method stub  
  48.         return null;  
  49.     }  
  50.   
  51.     public boolean supports(Class<?> clazz) {  
  52.         // TODO Auto-generated method stub  
  53.         return true;  
  54.     }  
  55.     //加载所有资源与权限的关系  
  56.     private Map<String, String> getResource() {  
  57.         Map<String, String> resourceMap = new HashMap<String, String>();  
  58.         List<User> users = systemService.getAllUser();  
  59.         for(User user:users){     
  60.             for(Role role : user.getUserRoles()) {  
  61.                 Set<Resource> resources = role.getRoleResources();  
  62.                 for(Resource resource : resources) {  
  63.                         String url = resource.getValue();  
  64.                         if(!resourceMap.containsKey(url)) {  
  65.                             resourceMap.put(url, role.getName());  
  66.                         }else{  
  67.                             String roleName = resourceMap.get(url);  
  68.                             resourceMap.put(url, roleName+","+role.getName());  
  69.                         }  
  70.                 }  
  71.             }  
  72.         }  
  73.         return resourceMap;  
  74.           
  75.     }  
  76.       
  77.     private void loadResourceDefine(){  
  78.         resourceMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();  
  79.         Map<String, String> resource = getResource();  
  80.         for(Map.Entry<String, String> entry:resource.entrySet()){  
  81.             Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();  
  82.             configAttributes.add(new SecurityConfig(entry.getValue()));  
  83.             resourceMap.put(new AntPathRequestMatcher(entry.getKey()), configAttributes);  
  84.         }  
  85.           
  86.     }  
  87.       
  88.       
  89.     //返回所请求资源所需要的权限  
  90.     public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {  
  91.           
  92.         HttpServletRequest request = ((FilterInvocation) object).getRequest();  
  93.         if(null==resourceMap){  
  94.             System.out.println("请求地址 " + ((FilterInvocation) object).getRequestUrl());  
  95.             loadResourceDefine();  
  96.             System.out.println("我需要的认证:"+resourceMap.toString());  
  97.         }  
  98.         for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {  
  99.             if (entry.getKey().matches(request)) {  
  100.                 return entry.getValue();  
  101.             }  
  102.         }  
  103.         return null;  
  104.     }  
  105.   
  106. }  


MyAccessDecisionManager

[java] view plaincopy
  1. package com.yindejin.system;  
  2.   
  3.   
  4. import java.util.Collection;  
  5. import java.util.Iterator;  
  6.   
  7. import org.springframework.security.access.AccessDecisionManager;  
  8. import org.springframework.security.access.AccessDeniedException;  
  9. import org.springframework.security.access.ConfigAttribute;  
  10. import org.springframework.security.authentication.InsufficientAuthenticationException;  
  11. import org.springframework.security.core.Authentication;  
  12. import org.springframework.security.core.GrantedAuthority;  
  13.   
  14. //3  
  15. public class MyAccessDecisionManager implements AccessDecisionManager {  
  16.       
  17.     public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {  
  18.         if(configAttributes == null) {  
  19.             return;  
  20.         }  
  21.         //所请求的资源拥有的权限(一个资源对多个权限)  
  22.         Iterator<ConfigAttribute> iterator = configAttributes.iterator();  
  23.         while(iterator.hasNext()) {  
  24.             ConfigAttribute configAttribute = iterator.next();  
  25.             //访问所请求资源所需要的权限  
  26.             String needPermission = configAttribute.getAttribute();  
  27.             System.out.println("needPermission is " + needPermission);  
  28.             //用户所拥有的权限authentication  
  29.             for(GrantedAuthority ga : authentication.getAuthorities()) {  
  30.                 if(needPermission.contains((ga.getAuthority()))) {  
  31.                     return;  
  32.                 }  
  33.             }  
  34.         }  
  35.         //没有权限让我们去捕捉  
  36.         throw new AccessDeniedException(" 没有权限访问!");  
  37.     }  
  38.   
  39.     public boolean supports(ConfigAttribute attribute) {  
  40.         // TODO Auto-generated method stub  
  41.         return true;  
  42.     }  
  43.   
  44.     public boolean supports(Class<?> clazz) {  
  45.         // TODO Auto-generated method stub  
  46.         return true;  
  47.     }  
  48.       
  49. }  


 

MyAuthenticationManager

[java] view plaincopy
  1. package com.yindejin.system;  
  2.   
  3. import org.springframework.security.core.userdetails.UserDetails;  
  4. import org.springframework.security.core.userdetails.UserDetailsService;  
  5. import org.springframework.security.core.userdetails.UsernameNotFoundException;  
  6.   
  7. import com.yindejin.system.service.ISystemService;  
  8. import com.yindejin.util.StringUtils;  
  9. import com.yindejin.vo.User;  
  10.   
  11. public class MyAuthenticationManager implements UserDetailsService {  
  12.       
  13.     private ISystemService systemService;  
  14.       
  15.       
  16.     public void setSystemService(ISystemService systemService) {  
  17.         this.systemService = systemService;  
  18.     }  
  19.   
  20.   
  21.     @Override  
  22.     public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {  
  23.         if(!StringUtils.isEmpty(userName)){  
  24.             throw new UsernameNotFoundException("用户名不能为空!");  
  25.         }  
  26.         User user = systemService.loginByUserName(userName);  
  27.         if (user == null) {  
  28.             throw new UsernameNotFoundException("用户名或密码错误!");  
  29.         }  
  30.         return user;  
  31.     }  
  32.   
  33. }  

 

User

[java] view plaincopy
  1. package com.yindejin.vo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.HashMap;  
  6. import java.util.HashSet;  
  7. import java.util.List;  
  8. import java.util.Map;  
  9. import java.util.Set;  
  10.   
  11. import javax.persistence.Transient;  
  12.   
  13. import org.springframework.security.core.GrantedAuthority;  
  14. import org.springframework.security.core.authority.GrantedAuthorityImpl;  
  15. import org.springframework.security.core.userdetails.UserDetails;  
  16.   
  17. /** 
  18.  * User entity. @author MyEclipse Persistence Tools 
  19.  */  
  20.   
  21. public class User implements UserDetails {  
  22.   
  23.     // Fields  
  24.   
  25.     private Integer id;  
  26.     private String name;  
  27.     private String password = "123456";  
  28.     private Integer disabled = 0;  
  29.     private String email;  
  30.     public String getEmail() {  
  31.         return email;  
  32.     }  
  33.   
  34.     public void setEmail(String email) {  
  35.         this.email = email;  
  36.     }  
  37.   
  38.     private Set<Role> userRoles = new HashSet<Role>();  
  39.     @Transient  
  40.     private Map<String, List<Resource>> roleResources;  
  41.   
  42.     // Constructors  
  43.   
  44.     public Integer getId() {  
  45.         return id;  
  46.     }  
  47.   
  48.     public void setId(Integer id) {  
  49.         this.id = id;  
  50.     }  
  51.   
  52.     public String getName() {  
  53.         return name;  
  54.     }  
  55.   
  56.     public void setName(String name) {  
  57.         this.name = name;  
  58.     }  
  59.   
  60.     public String getPassword() {  
  61.         return password;  
  62.     }  
  63.   
  64.     public void setPassword(String password) {  
  65.         this.password = password;  
  66.     }  
  67.   
  68.     public Integer getDisabled() {  
  69.         return disabled;  
  70.     }  
  71.   
  72.     public void setDisabled(Integer disabled) {  
  73.         this.disabled = disabled;  
  74.     }  
  75.   
  76.     public Set<Role> getUserRoles() {  
  77.         return userRoles;  
  78.     }  
  79.   
  80.     public void setUserRoles(Set<Role> userRoles) {  
  81.         this.userRoles = userRoles;  
  82.     }  
  83.   
  84.     /** default constructor */  
  85.     public User() {  
  86.     }  
  87.   
  88.   
  89.     public String getUsername() {  
  90.         return name;  
  91.     }  
  92.       
  93.     public boolean isAccountNonExpired() {  
  94.         return true;  
  95.     }  
  96.   
  97.     public boolean isAccountNonLocked() {  
  98.         return true;  
  99.     }  
  100.   
  101.     public boolean isCredentialsNonExpired() {  
  102.         return true;  
  103.     }  
  104.   
  105.     public boolean isEnabled() {  
  106.         return this.disabled==0?true:false;  
  107.     }  
  108.       
  109.     /** 
  110.      * @return the roleResources 
  111.      */  
  112.     public Map<String, List<Resource>> getRoleResources() {  
  113.         // init roleResources for the first time  
  114.         if(this.roleResources == null) {              
  115.             this.roleResources = new HashMap<String, List<Resource>>();  
  116.                   
  117.             for(Role role : this.userRoles) {  
  118.                 String roleName = role.getName();  
  119.                 Set<Resource> resources = role.getRoleResources();  
  120.                 for(Resource resource : resources) {  
  121.                     String key = roleName + "_" + resource.getType();  
  122.                         if(!this.roleResources.containsKey(key)) {  
  123.                             this.roleResources.put(key, new ArrayList<Resource>());  
  124.                     }  
  125.                         this.roleResources.get(key).add(resource);                    
  126.                 }  
  127.             }  
  128.                   
  129.         }  
  130.         return this.roleResources;  
  131.     }  
  132.   
  133.     @SuppressWarnings("deprecation")  
  134.     @Override  
  135.     public Collection<GrantedAuthority> getAuthorities() {  
  136.         Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();  
  137.         for(Role role : getUserRoles()){  
  138.             authSet.add(new GrantedAuthorityImpl(role.getName()));  
  139.         }  
  140.         return authSet;  
  141.     }  
  142.   
  143.       
  144.   
  145. }