Spring Security 3.0数据库动态实现权限控制

来源:互联网 发布:淘宝网店招牌制作 编辑:程序博客网 时间:2024/05/21 10:37
第一次接触Spring Security,在网上找了很多资料,有简单示例的,就是把用户名及权限信息配置在XML里面,但这种不太适合一般的项目!有些资料是翻译源代码讲解各个过滤器的作用以及其工作原理!由于项目时间紧所以求成心切的我看这些资料的时候总是很匆忙的跳步来看,到最后反而稀里糊涂,脑子里更乱,真心的希望有个狄仁杰中的元芳能在身边,这样我还能听取下他的意见:"元芳,你怎么看!"这两天静下来把之前看的那些详细看了看,最后感觉这玩意儿也不是那么那么让人抓狂! 

开发环境 SpringIDE 3.0、Spring Security 3.0.2、myibatis、Maven、MySql 
最前面的spring配置以及Maven管理架包、myibatis的配置就不说了 
首先: 
1、需要将所需要的JAR包在pom中配置 
 
2、在web.xml中添加spring security的过滤链 
Java代码  收藏代码
  1. <filter>  
  2.     <filter-name>springSecurityFilterChain</filter-name>  
  3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  4. </filter>  
  5.   
  6. <filter-mapping>  
  7.     <filter-name>springSecurityFilterChain</filter-name>  
  8.     <url-pattern>/*</url-pattern>  
  9. </filter-mapping>  

3、添加applicationContext-security.xml到根目录下 
内容如下: 
Java代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <b:beans xmlns="http://www.springframework.org/schema/security"  
  3.  xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.  xsi:schemaLocation="http://www.springframework.org/schema/beans   
  5.  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  6.     http://www.springframework.org/schema/security   
  7.     http://www.springframework.org/schema/security/spring-security-3.0.xsd">  
  8.   
  9.     <!-- <global-method-security pre-post-annotations="enabled" /> -->  
  10.       
  11.     <!-- access-denied-page配置访问失败页面 -->  
  12.     <http auto-config="true" access-denied-page="/accessDenied.htm">  
  13.         <!-- 不要过滤图片等静态资源,其中**代表可以跨越目录,*不可以跨越目录。 -->  
  14.           <intercept-url pattern="/**/*.jpg" filters="none" />  
  15.           <intercept-url pattern="/**/*.png" filters="none" />  
  16.           <intercept-url pattern="/**/*.gif" filters="none" />  
  17.           <intercept-url pattern="/**/*.css" filters="none" />  
  18.           <intercept-url pattern="/**/*.js" filters="none" />  
  19.           <intercept-url pattern="/login.htm*" filters="none"/>  
  20.           <!-- <intercept-url pattern="/index.htm" access="ROLE_USER,ROLE_ADMIN"/>  
  21.           <intercept-url pattern="/header.htm" access="ROLE_USER,ROLE_ADMIN"/>  
  22.           <intercept-url pattern="/left.htm" access="ROLE_USER,ROLE_ADMIN"/> -->  
  23.           <intercept-url pattern="/**" access="ROLE_USER"/>  
  24.         <!-- 配置登录页面 -->  
  25.         <form-login login-page="/login.htm"  
  26.             default-target-url="/" authentication-failure-url="/login.htm?error=true"  
  27.             login-processing-url="/springSecurityLogin"/>  
  28.         <!--"记住我"功能,采用持久化策略(将用户的登录信息存放在数据库表中) -->  
  29.         <!-- <remember-me/> -->  
  30.         <!-- 用户退出的跳转页面 -->  
  31.         <logout logout-success-url="/login.htm" invalidate-session="true"   
  32.             logout-url="/logout" />  
  33.         <!-- 会话管理,设置最多登录异常,error-if-maximum-exceeded = false为第二次登录就会使前一个登录失效 -->  
  34.          <session-management invalid-session-url="/error/errorPage.jsp">  
  35.             <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" />  
  36.         </session-management>  
  37.           
  38.         <!--添加自定义的过滤器 放在FILTER_SECURITY_INTERCEPTOR之前有效  -->  
  39.         <custom-filter ref="customFilterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />  
  40.     </http>  
  41.       
  42.     <!-- 配置认证管理器 -->  
  43.     <authentication-manager alias="authenticationManager">  
  44.         <authentication-provider user-service-ref="customUserDetailsService">  
  45.             <password-encoder hash="md5"/>  
  46.             <!-- <jdbc-user-service data-source-ref="dataSource"/> -->  
  47.         </authentication-provider>  
  48.     </authentication-manager>  
  49. </b:beans>  

上面是XML文件,需要说明的是:intercept-url节点需至少有一个拦截的,如果全部过滤图片或者是样式这些,spring框架启动的时候,就不会拦截任何URL,因为你没有配置相关的拦截的intercept-url,所以它就以为任何人都可以访问整个资源! 


其中的节点用途都有说明,就不在啰嗦 
4、创建CustomUserDetailsService、CustomAccessDecisionManager、CustomFilterSecurityInterceptor、CustomInvocationSecurityMetadataSource 
这4个类我定义的接口,有相应的实现类,在实现动态权限控制中这4个类都会用到 
a、CustomUserDetailsServiceImpl 实现 CustomUserDetailsService 继承自 org.springframework.security.core.userdetails.UserDetailsService,这个类主要是处理用户登录信息,在用户输入用户名和密码后,spring security会带着用户名调用类里面的loadUserByUsername(usrename)方法,在这里个人理解是,它没有用密码作为验证条件是通过用户名查出用户信息,然后把数据库中查出的用户密码和刚刚用户输入的存储在session中的密码做比较,然后判断该用户是否合法! 
Java代码  收藏代码
  1. package com.doone.wisdom.security.impl;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.List;  
  6.   
  7. import javax.annotation.Resource;  
  8.   
  9. import org.springframework.security.core.GrantedAuthority;  
  10. import org.springframework.security.core.authority.GrantedAuthorityImpl;  
  11. import org.springframework.security.core.userdetails.User;  
  12. import org.springframework.security.core.userdetails.UserDetails;  
  13. import org.springframework.security.core.userdetails.UsernameNotFoundException;  
  14. import org.springframework.stereotype.Service;  
  15.   
  16. import com.doone.wisdom.dao.security.UserDao;  
  17. import com.doone.wisdom.entity.security.RoleEntity;  
  18. import com.doone.wisdom.entity.security.UserEntity;  
  19. import com.doone.wisdom.security.service.CustomUserDetailsService;  
  20.   
  21. /**  
  22.  * TODO(这里用一句话描述这个类的职责). 
  23.  * @ClassName: CustomUserDetailsServiceImpl 
  24.  * @author Johnny_L_Q 
  25.  */  
  26. @Service("customUserDetailsService")  
  27. public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {  
  28.   
  29.     /** 
  30.      * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么). 
  31.      */  
  32.     private static final long serialVersionUID = 1L;  
  33.       
  34.     @Resource  
  35.     private UserDao userDao;  
  36.       
  37.   
  38.     /* 
  39.      * 根据用户名判断是否存在 
  40.      * <p>Title: loadUserByUsername</p> 
  41.      * <p>Description: </p> 
  42.      * @param arg0 
  43.      * @return 
  44.      * @throws UsernameNotFoundException 
  45.      * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) 
  46.      */  
  47.     @Override  
  48.     public UserDetails loadUserByUsername(String username)  
  49.             throws UsernameNotFoundException {  
  50.         UserEntity user = userDao.getUser(username);  
  51.           
  52.         if (null == user) {  
  53.             throw new UsernameNotFoundException("用户" + username + "不存在");  
  54.         }  
  55.           
  56.           
  57.         Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();  
  58.         List<String> list = userDao.getAuthoritiesByUsername(username);  
  59.         for (int i = 0; i < list.size(); i++) {  
  60.             auths.add(new GrantedAuthorityImpl(list.get(i)));  
  61.             System.out.println("loadUserByUsername : " + list.get(i));  
  62.         }  
  63.       //因为UserEntity实现了UserDetails,所以也可以直接返回user  
  64.         return new User(username, user.getPassword(), truetruetruetrue, auths);  
  65.     }  
  66.   
  67. }  



b、CustomAccessDecisionManagerImpl 实现 CustomAccessDecisionManager 继承自 org.springframework.security.access.AccessDecisionManager 
这个类主要是处理用户在访问某个URL的时候,就会通过访问该类的权限与登录用户所拥有的权限做比较,如果拥有权限,那你就可以到访问外星文明了,如果没有权限,那你就要被遣送回非洲,还会抛一个异常告诉你,你已经被遣送回非洲! 
Java代码  收藏代码
  1. package com.doone.wisdom.security.impl;  
  2.   
  3. import java.util.Collection;  
  4. import java.util.Iterator;  
  5.   
  6. import org.springframework.security.access.AccessDeniedException;  
  7. import org.springframework.security.access.ConfigAttribute;  
  8. import org.springframework.security.access.SecurityConfig;  
  9. import org.springframework.security.authentication.InsufficientAuthenticationException;  
  10. import org.springframework.security.core.Authentication;  
  11. import org.springframework.security.core.GrantedAuthority;  
  12. import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;  
  13. import org.springframework.security.provisioning.JdbcUserDetailsManager;  
  14. import org.springframework.stereotype.Service;  
  15.   
  16. import com.doone.wisdom.security.service.CustomAccessDecisionManager;  
  17.   
  18. /**  
  19.  *  
  20.  * AccessdecisionManager在Spring security中是很重要的。  
  21.  *   
  22.  * 在验证部分简略提过了,所有的Authentication实现需要保存在一个GrantedAuthority对象数组中。 这就是赋予给主体的权限。  
  23.  * GrantedAuthority对象通过AuthenticationManager 保存到  
  24.  * Authentication对象里,然后从AccessDecisionManager读出来,进行授权判断。  
  25.  *   
  26.  * Spring Security提供了一些拦截器,来控制对安全对象的访问权限,例如方法调用或web请求。  
  27.  * 一个是否允许执行调用的预调用决定,是由AccessDecisionManager实现的。 这个 AccessDecisionManager  
  28.  * 被AbstractSecurityInterceptor调用, 它用来作最终访问控制的决定。  
  29.  * 这个AccessDecisionManager接口包含三个方法:  
  30.  *   
  31.  * void decide(Authentication authentication, Object secureObject,  
  32.  * List<ConfigAttributeDefinition> config) throws AccessDeniedException; boolean  
  33.  * supports(ConfigAttribute attribute); boolean supports(Class clazz);  
  34.  *   
  35.  * 从第一个方法可以看出来,AccessDecisionManager使用方法参数传递所有信息,这好像在认证评估时进行决定。  
  36.  * 特别是,在真实的安全方法期望调用的时候,传递安全Object启用那些参数。 比如,让我们假设安全对象是一个MethodInvocation。  
  37.  * 很容易为任何Customer参数查询MethodInvocation,  
  38.  * 然后在AccessDecisionManager里实现一些有序的安全逻辑,来确认主体是否允许在那个客户上操作。  
  39.  * 如果访问被拒绝,实现将抛出一个AccessDeniedException异常。  
  40.  *   
  41.  * 这个 supports(ConfigAttribute) 方法在启动的时候被  
  42.  * AbstractSecurityInterceptor调用,来决定AccessDecisionManager  
  43.  * 是否可以执行传递ConfigAttribute。 supports(Class)方法被安全拦截器实现调用,  
  44.  * 包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型。   
  45.  * TODO(这里用一句话描述这个类的职责). 
  46.  * @ClassName: CustomAccessDecisionManagerImpl 
  47.  * @author Johnny_L_Q 
  48.  */  
  49. @Service("customAccessDecisionManager")  
  50. public class CustomAccessDecisionManagerImpl implements  
  51.         CustomAccessDecisionManager {  
  52.   
  53.     /* 
  54.      * <p>Title: decide</p> 
  55.      * <p>Description: </p> 
  56.      * @param arg0 
  57.      * @param arg1 
  58.      * @param arg2 
  59.      * @throws AccessDeniedException 
  60.      * @throws InsufficientAuthenticationException 
  61.      * @see org.springframework.security.access.AccessDecisionManager 
  62.      * #decide(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection) 
  63.      */  
  64.     @Override  
  65.     public void decide(Authentication authentication, Object object,  
  66.             Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,  
  67.             InsufficientAuthenticationException {  
  68.         if (null == configAttributes) {  
  69.             return;  
  70.         }  
  71.           
  72.         Iterator<ConfigAttribute> cons = configAttributes.iterator();  
  73.           
  74.         while(cons.hasNext()){  
  75.             ConfigAttribute ca = cons.next();  
  76.             String needRole = ((SecurityConfig) ca).getAttribute();  
  77.             //gra 为用户所被赋予的权限,needRole为访问相应的资源应具有的权限  
  78.             for (GrantedAuthority gra : authentication.getAuthorities()) {  
  79.                 if (needRole.trim().equals(gra.getAuthority().trim())) {  
  80.                     return;  
  81.                 }  
  82.             }  
  83.         }  
  84.         throw new AccessDeniedException("Access Denied");  
  85.     }  
  86.   
  87.     /* 
  88.      * <p>Title: supports</p> 
  89.      * <p>Description: </p> 
  90.      * @param arg0 
  91.      * @return 
  92.      * @see org.springframework.security.access.AccessDecisionManager#supports(org.springframework.security.access.ConfigAttribute) 
  93.      */  
  94.     @Override  
  95.     public boolean supports(ConfigAttribute arg0) {  
  96.         // TODO Auto-generated method stub  
  97.         return true;  
  98.     }  
  99.   
  100.     /* 
  101.      * <p>Title: supports</p> 
  102.      * <p>Description: </p> 
  103.      * @param arg0 
  104.      * @return 
  105.      * @see org.springframework.security.access.AccessDecisionManager#supports(java.lang.Class) 
  106.      */  
  107.     @Override  
  108.     public boolean supports(Class<?> arg0) {  
  109.         // TODO Auto-generated method stub  
  110.         return true;  
  111.     }  
  112. }  


c、CustomFilterSecurityInterceptorImpl 实现 CustomFilterSecurityInterceptor 继承 javax.servlet.Filter 
该类的目的是拦截的入口,首先启动的时候会注入注入里面的属性,然后当用户访问你配置过的URL的时候,就会被拦截进入到doFilter方法中,在调用infoke()方法进入到CustomAccessDecisionManagerImpl.decide()方法中将访问的url与配置的url的权限做比较 
Java代码  收藏代码
  1. package com.doone.wisdom.security.impl;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.annotation.Resource;  
  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.beans.factory.annotation.Qualifier;  
  13. import org.springframework.security.access.AccessDecisionManager;  
  14. import org.springframework.security.access.SecurityMetadataSource;  
  15. import org.springframework.security.access.intercept.AbstractSecurityInterceptor;  
  16. import org.springframework.security.access.intercept.InterceptorStatusToken;  
  17. import org.springframework.security.authentication.AuthenticationManager;  
  18. import org.springframework.security.web.FilterInvocation;  
  19. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
  20. import org.springframework.stereotype.Service;  
  21.   
  22. import com.doone.wisdom.security.service.CustomFilterSecurityInterceptor;  
  23.   
  24. /**   
  25.  * 该过滤器的主要作用就是通过spring著名的IoC生成securityMetadataSource。  
  26.  * securityMetadataSource相当于本包中自定义的CostomInvocationSecurityMetadataSourceService。  
  27.  * 该CostomInvocationSecurityMetadataSourceService的作用提从数据库提取权限和资源,装配到HashMap中,  
  28.  * 供Spring Security使用,用于权限校验。  
  29.  *   
  30.  * TODO(这里用一句话描述这个类的职责). 
  31.  * @ClassName: CustomFilterSecurityInterceptorImpl 
  32.  * @author Johnny_L_Q 
  33.  */  
  34. @Service("customFilterSecurityInterceptor")  
  35. public class CustomFilterSecurityInterceptorImpl extends  
  36.         AbstractSecurityInterceptor implements CustomFilterSecurityInterceptor {  
  37.   
  38.     @Resource  
  39.     @Qualifier("customInvocationSecurityMetadataSource")  
  40.     private FilterInvocationSecurityMetadataSource securityMetadataSource;  
  41.      
  42.   
  43.     @Resource  
  44.     @Qualifier("customAccessDecisionManager")  
  45.     @Override  
  46.     public void setAccessDecisionManager(  
  47.             AccessDecisionManager accessDecisionManager) {  
  48.         // TODO Auto-generated method stub  
  49.         super.setAccessDecisionManager(accessDecisionManager);  
  50.     }  
  51. /*    @Resource 
  52.     @Qualifier("customAccessDecisionManager") 
  53.     public AccessDecisionManager accessDecisionManager;*/  
  54.       
  55. /*    @Resource 
  56.     @Qualifier("authenticationManager") 
  57.     public AuthenticationManager authenticationManager;*/  
  58.       
  59.       
  60.     @Resource  
  61.     @Qualifier("authenticationManager")  
  62.     @Override  
  63.     public void setAuthenticationManager(AuthenticationManager newManager) {  
  64.         super.setAuthenticationManager(newManager);  
  65.     }  
  66.       
  67.     /* 
  68.      * <p>Title: doFilter</p> 
  69.      * <p>Description: </p> 
  70.      * @param arg0 
  71.      * @param arg1 
  72.      * @param arg2 
  73.      * @throws IOException 
  74.      * @throws ServletException 
  75.      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) 
  76.      */  
  77.     @Override  
  78.     public void doFilter(ServletRequest request, ServletResponse response,  
  79.             FilterChain chain) throws IOException, ServletException {  
  80.         FilterInvocation fi = new FilterInvocation(request, response, chain);  
  81.         infoke(fi);  
  82.   
  83.     }  
  84.   
  85.     /** 
  86.      * TODO(这里用一句话描述这个方法的作用). 
  87.      * @param fi  
  88.      * @throws ServletException  
  89.      * @throws IOException  
  90.      */  
  91.     private void infoke(FilterInvocation fi) throws IOException, ServletException {  
  92.         InterceptorStatusToken token = super.beforeInvocation(fi);  
  93.           
  94.         try {  
  95.             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
  96.         } finally {  
  97.             super.afterInvocation(token, null);  
  98.         }  
  99.           
  100.     }  
  101.   
  102.     /* 
  103.      * <p>Title: init</p> 
  104.      * <p>Description: </p> 
  105.      * @param arg0 
  106.      * @throws ServletException 
  107.      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) 
  108.      */  
  109.     @Override  
  110.     public void init(FilterConfig arg0) throws ServletException {  
  111.         // TODO Auto-generated method stub  
  112.   
  113.     }  
  114.   
  115.     /* 
  116.      * <p>Title: getSecureObjectClass</p> 
  117.      * <p>Description: </p> 
  118.      * @return 
  119.      * @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#getSecureObjectClass() 
  120.      */  
  121.     @Override  
  122.     public Class<?> getSecureObjectClass() {  
  123.         // TODO Auto-generated method stub  
  124.         return FilterInvocation.class;  
  125.     }  
  126.   
  127.     /* 
  128.      * <p>Title: obtainSecurityMetadataSource</p> 
  129.      * <p>Description: </p> 
  130.      * @return 
  131.      * @see org.springframework.security.access.intercept.AbstractSecurityInterceptor#obtainSecurityMetadataSource() 
  132.      */  
  133.     @Override  
  134.     public SecurityMetadataSource obtainSecurityMetadataSource() {  
  135.         // TODO Auto-generated method stub  
  136.         return this.securityMetadataSource;  
  137.     }  
  138.       
  139.     /* 
  140.      * <p>Title: destroy</p> 
  141.      * <p>Description: </p> 
  142.      * @see javax.servlet.Filter#destroy() 
  143.      */  
  144.     @Override  
  145.     public void destroy() {  
  146.         // TODO Auto-generated method stub  
  147.   
  148.     }  
  149.       
  150.   
  151.     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {  
  152.         return securityMetadataSource;  
  153.     }  
  154.       
  155.   
  156.     public void setSecurityMetadataSource(  
  157.             FilterInvocationSecurityMetadataSource securityMetadataSource) {  
  158.         this.securityMetadataSource = securityMetadataSource;  
  159.     }  
  160. }  

d、CustomFilterInvocationSecurityMetadataSourceImpl 实现 CustomFilterInvocationSecurityMetadataSource 继承自 
org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource 
该类的主要作用是在Spring Security的整个过滤链启动后,在容器启动的时候,程序就会进入到该类中的init()方法,init调用了loadResourceDefine()方法,该方法的主要目的是将数据库中的所有资源与权限读取到本地缓存中保存起来!类中的resourceMap就是保存的所有资源和权限的集合,URL为Key,权限作为Value! 
Java代码  收藏代码
  1. package com.doone.wisdom.security.impl;  
  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.   
  9. import javax.annotation.PostConstruct;  
  10. import javax.annotation.Resource;  
  11.   
  12. import org.springframework.security.access.ConfigAttribute;  
  13. import org.springframework.security.access.SecurityConfig;  
  14. import org.springframework.security.web.FilterInvocation;  
  15. import org.springframework.security.web.util.AntUrlPathMatcher;  
  16. import org.springframework.security.web.util.UrlMatcher;  
  17. import org.springframework.stereotype.Service;  
  18.   
  19. import com.doone.wisdom.entity.security.AuthorityEntity;  
  20. import com.doone.wisdom.entity.security.RoleEntity;  
  21. import com.doone.wisdom.security.service.CustomInvocationSecurityMetadataSource;  
  22. import com.doone.wisdom.service.iface.AuthorityService;  
  23. import com.doone.wisdom.service.iface.ResourceService;  
  24.   
  25. /**  
  26.  * TODO(这里用一句话描述这个类的职责). 
  27.  * @ClassName: CustomInvocationSecurityMetadataSourceImpl 
  28.  * @author Johnny_L_Q 
  29.  */  
  30. @Service("customInvocationSecurityMetadataSource")  
  31. public class CustomInvocationSecurityMetadataSourceImpl implements  
  32.         CustomInvocationSecurityMetadataSource {  
  33.   
  34.     @Resource  
  35.     private ResourceService resourceService;  
  36.       
  37.     @Resource  
  38.     private AuthorityService authorityService;  
  39.   
  40.     private UrlMatcher urlMatcher = new AntUrlPathMatcher();  
  41.   
  42.     //private AntPathRequestMatcher pathMatcher;  
  43.   
  44.     private HashMap<String, Collection<ConfigAttribute>> resourceMap = null;  
  45.   
  46.     /** 
  47.      * 
  48.      * 自定义方法,这个类放入到Spring容器后,  
  49.      * 指定init为初始化方法,从数据库中读取资源  
  50.      * TODO(这里用一句话描述这个方法的作用). 
  51.      */  
  52.     @PostConstruct  
  53.     public void init() {  
  54.         loadResourceDefine();  
  55.     }  
  56.   
  57.     /** 
  58.      *  
  59.      * TODO(程序启动的时候就加载所有资源信息). 
  60.      */  
  61.     private void loadResourceDefine() {  
  62.   
  63.         // 在Web服务器启动时,提取系统中的所有权限。  
  64.         //sql = "select authority_name from pub_authorities";  
  65.   
  66.         List<AuthorityEntity> query = authorityService.getAllAuthoritys();  
  67.   
  68.         /**//* 
  69.              * 应当是资源为key, 权限为value。 资源通常为url, 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问。 
  70.              * sparta 
  71.              */  
  72.         resourceMap = new HashMap<String, Collection<ConfigAttribute>>();  
  73.   
  74.         for (AuthorityEntity auth : query) {  
  75.             String authName = auth.getAuthorityName();  
  76.               
  77.             ConfigAttribute ca = new SecurityConfig(auth.getAuthorityName());  
  78.   
  79.             List<String> resources = resourceService.getResourcesByAuthName(authName);  
  80.            
  81.   
  82.             for (String str : resources) {  
  83.                 //String authName = auth2.getAuthorityName();  
  84.                 String url = str;  
  85.   
  86.                 /**//* 
  87.                      * 判断资源文件和权限的对应关系,如果已经存在相关的资源url,则要通过该url为key提取出权限集合,将权限增加到权限集合中。 
  88.                      * sparta 
  89.                      */  
  90.                 if (resourceMap.containsKey(url)) {  
  91.   
  92.                     Collection<ConfigAttribute> value = resourceMap.get(url);  
  93.                     value.add(ca);  
  94.                     resourceMap.put(url, value);  
  95.                 } else {  
  96.                     Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();  
  97.                     atts.add(ca);  
  98.                     resourceMap.put(url, atts);  
  99.                 }  
  100.   
  101.             }  
  102.   
  103.         }  
  104.   
  105.     }  
  106.   
  107.     /** 
  108.      * TODO(自定义方法,将List<Role>集合转换为框架需要的Collection<ConfigAttribute>集合). 
  109.      * @param roles 角色集合 
  110.      * @return list 封装好的Collection集合 
  111.      */  
  112.     private Collection<ConfigAttribute> listToCollection(List<RoleEntity> roles) {  
  113.         List<ConfigAttribute> list = new ArrayList<ConfigAttribute>();  
  114.   
  115.         for (RoleEntity role : roles) {  
  116.             list.add(new SecurityConfig(role.getRoleName()));  
  117.   
  118.         }  
  119.         return list;  
  120.     }  
  121.   
  122.     /* 
  123.      * <p>Title: getAllConfigAttributes</p> 
  124.      * <p>Description: </p> 
  125.      * @return 
  126.      * @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes() 
  127.      */  
  128.     @Override  
  129.     public Collection<ConfigAttribute> getAllConfigAttributes() {  
  130.         return null;  
  131.     }  
  132.   
  133.     /* 
  134.      * <p>Title: getAttributes</p> 
  135.      * <p>Description: </p> 
  136.      * @param arg0 
  137.      * @return 
  138.      * @throws IllegalArgumentException 
  139.      * @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object) 
  140.      */  
  141.     @Override  
  142.     public Collection<ConfigAttribute> getAttributes(Object object)  
  143.             throws IllegalArgumentException {  
  144.         //object 是一个URL ,为用户请求URL  
  145.         String url = ((FilterInvocation)object).getRequestUrl();  
  146.        if("/".equals(url)){  
  147.            return null;  
  148.        }  
  149.         int firstQuestionMarkIndex = url.indexOf(".");  
  150.         //判断请求是否带有参数 如果有参数就去掉后面的后缀和参数(/index.do  --> /index)  
  151.         if(firstQuestionMarkIndex != -1){  
  152.             url = url.substring(0,firstQuestionMarkIndex);  
  153.         }  
  154.           
  155.         Iterator<String> ite = resourceMap.keySet().iterator();  
  156.         //取到请求的URL后与上面取出来的资源做比较  
  157.         while (ite.hasNext()) {  
  158.             String resURL = ite.next();  
  159.             if(urlMatcher.pathMatchesUrl(url, resURL)){  
  160.                 return resourceMap.get(resURL);  
  161.             }  
  162.         }  
  163.         return null;  
  164.     }  
  165.   
  166.   
  167.     /* 
  168.      * <p>Title: supports</p> 
  169.      * <p>Description: </p> 
  170.      * @param arg0 
  171.      * @return 
  172.      * @see org.springframework.security.access.SecurityMetadataSource#supports(java.lang.Class) 
  173.      */  
  174.     @Override  
  175.     public boolean supports(Class<?> arg0) {  
  176.         // TODO Auto-generated method stub  
  177.         return true;  
  178.     }  
  179. }  



以上就是spring security所要用到的代码,接下来是数据库 
5、数据库设计的话就是标准的7张表 
1、pub_authorities 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:29:52 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_authorities  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_authorities` (  
  15.   `authority_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  16.   `authority_name` varchar(40) COLLATE utf8_bin NOT NULL,  
  17.   `authority_desc` varchar(100) COLLATE utf8_bin DEFAULT NULL,  
  18.   `enabled` int(10) NOT NULL,  
  19.   `issys` int(10) NOT NULL,  
  20.   PRIMARY KEY (`authority_id`)  
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  22.   
  23. -- ----------------------------  
  24. -- Records   
  25. -- ----------------------------  
  26. INSERT INTO `pub_authorities` VALUES ('1''ROLE_ADMIN''首页广告条管理''1''0');  
  27. INSERT INTO `pub_authorities` VALUES ('2''ROLE_USER''首页''1''0');  

2、pub_resources 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:30:25 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_resources  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_resources` (  
  15.   `resource_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  16.   `resource_name` varchar(100) COLLATE utf8_bin NOT NULL,  
  17.   `resource_type` varchar(40) COLLATE utf8_bin NOT NULL,  
  18.   `priority` int(10) NOT NULL,  
  19.   `resource_string` varchar(200) COLLATE utf8_bin NOT NULL,  
  20.   `resource_desc` varchar(100) COLLATE utf8_bin DEFAULT NULL,  
  21.   `enabled` int(10) NOT NULL,  
  22.   `issys` int(10) NOT NULL,  
  23.   PRIMARY KEY (`resource_id`)  
  24. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  25.   
  26. -- ----------------------------  
  27. -- Records   
  28. -- ----------------------------  
  29. INSERT INTO `pub_resources` VALUES ('1''首页广告条管理''action''0''/funcPages/adManager''首页广告条管理''1''0');  
  30. INSERT INTO `pub_resources` VALUES ('2''首页''action''0''/index''首页''1''0');  

3、pub_authorities_resources 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:30:17 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_authorities_resources  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_authorities_resources` (  
  15.   `id` varchar(32) COLLATE utf8_bin NOT NULL,  
  16.   `authority_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  17.   `resource_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  18.   PRIMARY KEY (`id`),  
  19.   KEY `fk_res_aut` (`authority_id`),  
  20.   KEY `fk_res` (`resource_id`),  
  21.   CONSTRAINT `fk_res` FOREIGN KEY (`resource_id`) REFERENCES `pub_resources` (`resource_id`),  
  22.   CONSTRAINT `fk_res_aut` FOREIGN KEY (`authority_id`) REFERENCES `pub_authorities` (`authority_id`)  
  23. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  24.   
  25. -- ----------------------------  
  26. -- Records   
  27. -- ----------------------------  
  28. INSERT INTO `pub_authorities_resources` VALUES ('1''1''1');  
  29. INSERT INTO `pub_authorities_resources` VALUES ('2''2''2');  

4、pub_roles 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:30:30 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_roles  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_roles` (  
  15.   `role_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  16.   `role_name` varchar(100) COLLATE utf8_bin NOT NULL,  
  17.   `role_desc` varchar(100) COLLATE utf8_bin DEFAULT NULL,  
  18.   `enabled` int(10) NOT NULL,  
  19.   `issys` int(10) NOT NULL COMMENT '角色表',  
  20.   PRIMARY KEY (`role_id`)  
  21. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  22.   
  23. -- ----------------------------  
  24. -- Records   
  25. -- ----------------------------  
  26. INSERT INTO `pub_roles` VALUES ('1''ROLE_ADMIN''系统登录''1''0');  
  27. INSERT INTO `pub_roles` VALUES ('2''ROLE_USER''普通用户''1''0');  

5、pub_roles_authorities 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:30:36 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_roles_authorities  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_roles_authorities` (  
  15.   `id` varchar(32) COLLATE utf8_bin NOT NULL,  
  16.   `role_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  17.   `authority_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  18.   PRIMARY KEY (`id`),  
  19.   KEY `fk_aut_role` (`role_id`),  
  20.   KEY `fk_aut` (`authority_id`),  
  21.   CONSTRAINT `fk_aut` FOREIGN KEY (`authority_id`) REFERENCES `pub_authorities` (`authority_id`),  
  22.   CONSTRAINT `fk_aut_role` FOREIGN KEY (`role_id`) REFERENCES `pub_roles` (`role_id`)  
  23. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  24.   
  25. -- ----------------------------  
  26. -- Records   
  27. -- ----------------------------  
  28. INSERT INTO `pub_roles_authorities` VALUES ('1''1''1');  
  29. INSERT INTO `pub_roles_authorities` VALUES ('2''1''2');  
  30. INSERT INTO `pub_roles_authorities` VALUES ('3''2''2');  

6、pub_users 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:30:42 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_users  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_users` (  
  15.   `user_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  16.   `user_account` varchar(30) COLLATE utf8_bin NOT NULL,  
  17.   `user_name` varchar(40) COLLATE utf8_bin NOT NULL,  
  18.   `user_password` varchar(100) COLLATE utf8_bin NOT NULL,  
  19.   `enabled` int(10) NOT NULL,  
  20.   `issys` int(10) NOT NULL,  
  21.   `user_desc` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '用户表',  
  22.   PRIMARY KEY (`user_id`)  
  23. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  24.   
  25. -- ----------------------------  
  26. -- Records   
  27. -- ----------------------------  
  28. INSERT INTO `pub_users` VALUES ('1''admin''admin''21232f297a57a5a743894a0e4a801fc3''1''1''超级管理员');  
  29. INSERT INTO `pub_users` VALUES ('2''user''user''ee11cbb19052e40b07aac0ca060c23ee''1''0''普通用户');  

7、pub_users_roles 
Java代码  收藏代码
  1. /* 
  2. MySQL Data Transfer 
  3. Source Host: localhost 
  4. Source Database: wisdom 
  5. Target Host: localhost 
  6. Target Database: wisdom 
  7. Date: 2012/10/19 9:30:48 
  8. */  
  9.   
  10. SET FOREIGN_KEY_CHECKS=0;  
  11. -- ----------------------------  
  12. -- Table structure for pub_users_roles  
  13. -- ----------------------------  
  14. CREATE TABLE `pub_users_roles` (  
  15.   `id` varchar(32) CHARACTER SET utf8 NOT NULL,  
  16.   `user_id` varchar(32) COLLATE utf8_bin NOT NULL,  
  17.   `role_id` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '角色和用户中间表',  
  18.   PRIMARY KEY (`id`),  
  19.   KEY `fk_user` (`user_id`),  
  20.   KEY `fk_role` (`role_id`),  
  21.   CONSTRAINT `fk_role` FOREIGN KEY (`role_id`) REFERENCES `pub_roles` (`role_id`),  
  22.   CONSTRAINT `fk_user` FOREIGN KEY (`user_id`) REFERENCES `pub_users` (`user_id`)  
  23. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;  
  24.   
  25. -- ----------------------------  
  26. -- Records   
  27. -- ----------------------------  
  28. INSERT INTO `pub_users_roles` VALUES ('1''1''1');  
  29. INSERT INTO `pub_users_roles` VALUES ('2''2''2');  




在最开始我运行的时候,我pub_authoritys表中存储的是AUTH_***的东西,但是好像spring security只认识ROLE_为前缀的权限,只有是ROLE_为前缀的它才能做比较,所以有一个地方需要注意,CustomInvocationSecurityMetadataSourceImpl.loadResourceDefine()方法中的resourceMap中的URL对于的权限必须是ROLE_为前缀的数据!如果你不确定的话,可以在方法在吧resourceMap的值打印出来看看! 
在这里我提供下几个类中做用到的查询方法的SQL,这些都是基于myibatis的SQL: 

1、getAuthoritiesByUsername(String username) 
Java代码  收藏代码
  1. select b.authority_name   
  2.          from  
  3.          PUB_ROLES a,  
  4.          PUB_AUTHORITIES b,  
  5.          PUB_ROLES_AUTHORITIES c   
  6.          where c.role_id = a.role_id and c.authority_id = b.authority_id and a.role_name in   
  7.          (select role_name from  
  8.          PUB_USERS_ROLES ur,  
  9.          PUB_USERS u,  
  10.          PUB_ROLES r  
  11.          where ur.user_id = u.user_id and ur.role_id = r.role_id and u.user_name = #{username}  
  12.          )  


2、getUser(String username) 
Java代码  收藏代码
  1. select * from   
  2.          PUB_USERS u  
  3.          where u.user_name = #{username}  


3、getResourcesByAuthName(String authName) 
Java代码  收藏代码
  1. select b.resource_string from PUB_AUTHORITIES_RESOURCES a ,PUB_RESOURCES b, PUB_AUTHORITIES c  
  2.          where a.resource_id = b.resource_id and a.authority_id = c.authority_id and c.authority_name = #{authName}  


4、getAllAuthoritys() 
Java代码  收藏代码
  1. select * from pub_authorities  
0 0
原创粉丝点击