`
solomongg
  • 浏览: 51577 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

spring security 3.0 实现认证与授权

阅读更多

先看一下spring security 官方对以下几个类或接口的解释,因为这个几个类在程序中会使用到;
ConfigAttribute:Stores a security system related configuration attribute.
SecurityConfig:ConfigAttribute的实现类。
GrantedAuthority:Represents an authority granted to an Authentication object.
GrantedAuthorityImpl:GrantedAuthority的实现类。
UserDetails:Provides core user information.
Authentication:Represents the token for an authentication request or for an authenticated principal once the request has been processed by the AuthenticationManager.authenticate(Authentication) method.
UserDetailsService:Core interface which loads user-specific data.
FilterInvocationSecurityMetadataSource:Marker interface for SecurityMetadataSource implementations that are designed to perform lookups keyed on FilterInvocations.
AccessDecisionManager:Makes a final access control (authorization) decision.

 

定义四张表:用户表、角色表、资源表、组织机构表(可选)

 

首先需要在web.xml文件中添加以下配置:

Web.xml代码  收藏代码
  1. <filter>  
  2.     <filter-name>springSecurityFilterChain</filter-name>  
  3.     <filter-class>  
  4.         org.springframework.web.filter.DelegatingFilterProxy  
  5.     </filter-class>  
  6. </filter>  
  7. <filter-mapping>  
  8.     <filter-name>springSecurityFilterChain</filter-name>  
  9.     <url-pattern>/*</url-pattern>  
  10. </filter-mapping>  

 

接着配置spring security的配置文件:

Xml代码  收藏代码
  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  
  6.            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7.            http://www.springframework.org/schema/security  
  8.            http://www.springframework.org/schema/security/spring-security-3.0.xsd">   
  9.   
  10.     <!-- access-denied-page:定义没有权限时跳转的页面 ;use-expressions:true表示使用表达式定义忽略拦截资源列表-->   
  11.     < http   auto-config = "true"   access-denied-page = "/accessDenied.do"   use-expressions = "true" >   
  12.         <!-- 忽略拦截资源定义 -->   
  13.         < intercept-url   pattern = "/showLogin.do*"   filters = "none"   />   
  14.         < intercept-url   pattern = "/scripts/**"   filters = "none"   />   
  15.         < intercept-url   pattern = "/images/**"   filters = "none"   />   
  16.         < intercept-url   pattern = "/styles/**"   filters = "none"   />   
  17.         < intercept-url   pattern = "/dwr/**"   filters = "none"   />   
  18.         <!-- isAuthenticated()表示只有通过验证的用户才能访问 -->   
  19.         < intercept-url   pattern = "/**"   access = "isAuthenticated()"   />   
  20.         < intercept-url   pattern = "/main.do*"   access = "isAuthenticated()"   />   
  21.           
  22.         <!-- max-sessions=1:禁止2次登陆;ession-fixation-protection="none":防止伪造sessionid攻击,用户登录成功后会销毁用户当前的session,-->   
  23.         <!-- 创建新的session并把用户信息复制到新session中 ;invalid-session-url:定义session超时跳转页面 -->   
  24.          < session-management   invalid-session-url = "/timeout.jsp"   session-fixation-protection = "none" >   
  25.             < concurrency-control   max-sessions = "1"   />     
  26.         </ session-management >   
  27.           
  28.         <!-- 表单验证 -->   
  29.         < form-login   login-page = "/showLogin.do"   authentication-failure-url = "/showLogin.do?error=true"   always-use-default-target = "true"   default-target-url = "/login.do?error=false"   />   
  30.         <!-- 退出系统跳转页面 -->    
  31.         < logout   invalidate-session = "true"   logout-success-url = "/showLogin.do"   />   
  32.         <!-- 免登陆验证 -->   
  33.         < remember-me   />   
  34.         <!-- 自定义拦截器(这里和spring security2的配置有点不同) -->   
  35.         < custom-filter   before = "FILTER_SECURITY_INTERCEPTOR"   ref = "securityFilter"   />   
  36.     </ http >   
  37.       
  38.     < beans:bean   id = "securityFilter"   class = "xxx.xxx.xxx.commons.permissionengine.web.security.FilterSecurityInterceptor" >   
  39.         < beans:property   name = "authenticationManager"   ref = "authenticationManager"   />   
  40.         < beans:property   name = "accessDecisionManager"   ref = "securityAccessDecisionManager"   />   
  41.         < beans:property   name = "securityMetadataSource"   ref = "securityMetadataSource"   />   
  42.     </ beans:bean >   
  43.       
  44.     < authentication-manager   alias = "authenticationManager" >   
  45.         < authentication-provider   user-service-ref = "securityUserDetailService" >   
  46.             <!-- 密码采用MD5算法加密 -->   
  47.             < password-encoder   hash = "md5"   />   
  48.         </ authentication-provider >   
  49.     </ authentication-manager >   
  50.       
  51.     <!-- 用户拥有的权限 -->   
  52.     < beans:bean   id = "securityUserDetailService"   class = "xxx.xxx.xxx.commons.permissionengine.web.security.SecurityUserDetailService"   />   
  53.     <!-- 用户是否拥有所请求资源的权限 -->   
  54.     < beans:bean   id = "securityAccessDecisionManager"   class = "xxx.xxx.xxx.commons.permissionengine.web.security.SecurityAccessDecisionManager"   />   
  55.     <!-- 资源与权限对应关系 -->   
  56.     < beans:bean   id = "securityMetadataSource"   class = "xxx.xxx.xxx.commons.permissionengine.web.security.SecurityMetadataSource"   />   
  57. </ beans:beans >   

 

接着需要写一个类实现UserDetails接口,这个并不是我们系统的用户,它只是一个VO,
用于保存从spring security上下文环境中获取到登录用户,因为从spring security上下文环境中获取登录用户的返回值就是UserDetails的实现类:

Java代码  收藏代码
  1. package  xxx.xxx.xxx.commons.permissionengine.entity;  
  2.   
  3. import  java.util.Collection;  
  4.   
  5. import  org.springframework.security.core.GrantedAuthority;  
  6. import  org.springframework.security.core.userdetails.UserDetails;  
  7.   
  8. public   class  UserDetailInfo  implements  UserDetails {  
  9.   
  10.     private   static   final   long  serialVersionUID = 6137804370301413132L;  
  11.       
  12.     private  String userName;  
  13.       
  14.     private  String password;  
  15.       
  16.     private  Collection<GrantedAuthority> authorities;  
  17.       
  18.     public  UserDetailInfo() {}  
  19.   
  20.     @Override   
  21.     public  Collection<GrantedAuthority> getAuthorities() {  
  22.         return  authorities;  
  23.     }  
  24.   
  25.     @Override   
  26.     public  String getPassword() {  
  27.         return  password;  
  28.     }  
  29.   
  30.     @Override   
  31.     public  String getUsername() {  
  32.         return  userName;  
  33.     }  
  34.   
  35.     @Override   
  36.     public   boolean  isAccountNonExpired() {  
  37.         return   true ;  
  38.     }  
  39.   
  40.     @Override   
  41.     public   boolean  isAccountNonLocked() {  
  42.         return   true ;  
  43.     }  
  44.   
  45.     @Override   
  46.     public   boolean  isCredentialsNonExpired() {  
  47.         return   true ;  
  48.     }  
  49.   
  50.     @Override   
  51.     public   boolean  isEnabled() {  
  52.         return   true ;  
  53.     }  
  54.   
  55.     public  String getUserName() {  
  56.         return  userName;  
  57.     }  
  58.   
  59.     public   void  setUserName(String userName) {  
  60.         this .userName = userName;  
  61.     }  
  62.   
  63.     public   void  setPassword(String password) {  
  64.         this .password = password;  
  65.     }  
  66.   
  67.     public   void  setAuthorities(Collection<GrantedAuthority> authorities) {  
  68.         this .authorities = authorities;  
  69.     }  
  70. }  

 

接着自定义一个继承了AbstractSecurityInterceptor的filter:

Java代码  收藏代码
  1. package  xxx.xxx.xxx.commons.permissionengine.web.security;  
  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  FilterSecurityInterceptor  extends  AbstractSecurityInterceptor  implements  Filter {  
  19.       
  20.     private  FilterInvocationSecurityMetadataSource securityMetadataSource;  
  21.   
  22.     @Override   
  23.     public   void  destroy() {  
  24.         // TODO Auto-generated method stub   
  25.     }  
  26.   
  27.     @Override   
  28.     public   void  doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)  throws  IOException, ServletException {  
  29.         FilterInvocation invocation = new  FilterInvocation(request, response, filterChain);  
  30.         invoke(invocation);  
  31.     }  
  32.       
  33.     public   void  invoke(FilterInvocation filterInvocation)  throws  IOException, ServletException {  
  34.         InterceptorStatusToken token = super .beforeInvocation(filterInvocation);  
  35.         try  {  
  36.             filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());  
  37.         } finally  {  
  38.             super .afterInvocation(token,  null );  
  39.         }  
  40.     }  
  41.   
  42.     @Override   
  43.     public   void  init(FilterConfig arg0)  throws  ServletException {  
  44.         // TODO Auto-generated method stub   
  45.     }  
  46.   
  47.     @Override   
  48.     public  Class<?  extends  Object> getSecureObjectClass() {  
  49.         return  FilterInvocation. class ;  
  50.     }  
  51.   
  52.     @Override   
  53.     public  SecurityMetadataSource obtainSecurityMetadataSource() {  
  54.         return   this .securityMetadataSource;  
  55.     }  
  56.   
  57.     public   void  setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {  
  58.         this .securityMetadataSource = securityMetadataSource;  
  59.     }  
  60.   
  61.     public  FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {  
  62.         return   this .securityMetadataSource;  
  63.     }  
  64. }  

 

接着定义一个类,实现了UserDetailsService接口,主要用于获取登录用户信息和用户所具有的角色

Java代码  收藏代码
  1. package  xxx.xxx.xxx.commons.permissionengine.web.security;  
  2.   
  3.   
  4. import  java.util.ArrayList;  
  5. import  java.util.Collection;  
  6. import  java.util.Set;  
  7.   
  8. import  javax.annotation.Resource;  
  9.   
  10. import  org.springframework.dao.DataAccessException;  
  11. import  org.springframework.security.core.GrantedAuthority;  
  12. import  org.springframework.security.core.authority.GrantedAuthorityImpl;  
  13. import  org.springframework.security.core.userdetails.UserDetails;  
  14. import  org.springframework.security.core.userdetails.UserDetailsService;  
  15. import  org.springframework.security.core.userdetails.UsernameNotFoundException;  
  16.   
  17. import  xxx.xxx.xxx.commons.permissionengine.entity.Role;  
  18. import  xxx.xxx.xxx.commons.permissionengine.entity.User;  
  19. import  xxx.xxx.xxx.commons.permissionengine.entity.UserDetailInfo;  
  20. import  xxx.xxx.xxx.commons.permissionengine.service.IUserService;  
  21.   
  22. public   class  SecurityUserDetailService  implements  UserDetailsService {  
  23.   
  24.     private  IUserService userService;  
  25.       
  26.     /**  
  27.      * 获取登录用户信息并添加到security上下文环境  
  28.      */   
  29.     @Override   
  30.     public  UserDetails loadUserByUsername(String name) throws  UsernameNotFoundException, DataAccessException {  
  31.         //定义存放用户角色信息的集合   
  32.         Collection<GrantedAuthority> authorities = new  ArrayList<GrantedAuthority>();  
  33.         //通过已经经过验证的登录用户的用户名查找登录用户信息   
  34.         User user = userService.findUserByProperty("name" , name);  
  35.         //定义一个userDetailInfo对象,该类实现了spring security UserDetails接口,因为已经经过验证的登录用户会保持在   
  36.         //spring security上下文环境中,通过该上下文环境获取登录用户信息返回的是UserDetails类型,因此需要定义一个类实现该接口   
  37.         UserDetailInfo userDetailInfo = null ;  
  38.         if (user !=  null ) {  
  39.             //获取登录用户信息的角色列表   
  40.             Set<Role> roles = user.getRoles();  
  41.             for (Role role : roles) {  
  42.                 //利用角色用户具有的角色的编号构造一个GrantedAuthority对象,并把该对象添加到集合中   
  43.                 GrantedAuthorityImpl grantedAuthorityImpl = new  GrantedAuthorityImpl( "ROLE_" +role.getNo());  
  44.                 authorities.add(grantedAuthorityImpl);  
  45.             }  
  46.             userDetailInfo = new  UserDetailInfo();  
  47.             userDetailInfo.setUserName(user.getName());  
  48.             userDetailInfo.setPassword(user.getPassword());  
  49.             //把角色信息添加到userDetailInfo对象中   
  50.             userDetailInfo.setAuthorities(authorities);  
  51.         }  
  52.         return  userDetailInfo;  
  53.     }  
  54.       
  55.     @Resource (name =  "userService" )  
  56.     public   void  setUserService(IUserService userService) {  
  57.         this .userService = userService;  
  58.     }  
  59. }  

 

再接着定义一个实现了FilterInvocationSecurityMetadataSource的类:

Java代码  收藏代码
  1. package  xxx.xxx.xxx.commons.permissionengine.web.security;  
  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.Map;  
  8.   
  9. import  javax.annotation.Resource;  
  10.   
  11. import  org.springframework.security.access.ConfigAttribute;  
  12. import  org.springframework.security.access.SecurityConfig;  
  13. import  org.springframework.security.web.FilterInvocation;  
  14. import  org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
  15. import  org.springframework.security.web.util.AntUrlPathMatcher;  
  16. import  org.springframework.security.web.util.UrlMatcher;  
  17.   
  18. import  xxx.xxx.xxx.commons.permissionengine.service.IMenuService;  
  19.   
  20. /**  
  21.  * 资源源数据管理器  
  22.  * @author Keven  
  23.  *  
  24.  */   
  25. public   class  SecurityMetadataSource  implements  FilterInvocationSecurityMetadataSource {  
  26.       
  27.     private  IMenuService menuService;  
  28.     //定义一个url匹配工具类   
  29.     private  UrlMatcher urlMatcher =  new  AntUrlPathMatcher();  
  30.       
  31.     private   static  Map<String, Collection<ConfigAttribute>> menuMap =  null ;  
  32.       
  33.     //该构造方法由spring容器调用   
  34.     public  SecurityMetadataSource() {  
  35.         loadMenuDefine();  
  36.     }  
  37.       
  38.     private   void  loadMenuDefine() {  
  39.         menuMap = new  HashMap<String, Collection<ConfigAttribute>>();  
  40.         //初始化匿名用户所拥有的权限   
  41.         Collection<ConfigAttribute> guestAtts = new  ArrayList<ConfigAttribute>();  
  42.         ConfigAttribute guestAttribute = new  SecurityConfig( "ROLE_Guest" );  
  43.         guestAtts.add(guestAttribute);  
  44.         menuMap.put("/showLogin.do*" , guestAtts);  
  45.     }  
  46.   
  47.     @Override   
  48.     public  Collection<ConfigAttribute> getAllConfigAttributes() {  
  49.         return   null ;  
  50.     }  
  51.   
  52.     @Override   
  53.     public  Collection<ConfigAttribute> getAttributes(Object object)  throws  IllegalArgumentException {  
  54.         //获取请求url   
  55.         String url = ((FilterInvocation)object).getRequestUrl();  
  56.         //从数据库获取资源与角色的对应关系,并设置初始化的资源_角色到该Map   
  57.         menuService.setMenuMap(menuMap);  
  58.         //获取资源列表   
  59.         Iterator<String> iter = menuMap.keySet().iterator();  
  60.         while (iter.hasNext()) {  
  61.             String menuUrl = iter.next();  
  62.             //防止把null值加入到map,报空指针异常   
  63.             if (menuUrl !=  null ) {  
  64.                 //请求url与角色所拥有的权限做匹配   
  65.                 if (urlMatcher.pathMatchesUrl(menuUrl, url))  
  66.                     return  menuMap.get(menuUrl);  
  67.             }  
  68.         }  
  69.         return   null ;  
  70.     }  
  71.   
  72.     @Override   
  73.     public   boolean  supports(Class<?> clazz) {  
  74.         return   true ;  
  75.     }  
  76.   
  77.     @Resource (name =  "menuService" )  
  78.     public   void  setMenuService(IMenuService menuService) {  
  79.         this .menuService = menuService;  
  80.     }  
  81. }  

 

再接着定义一个实现了AccessDecisionManager的类:

Java代码  收藏代码
  1. package  xxx.xxx.xxx.commons.permissionengine.web.security;  
  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. /**  
  15.  * 决策管理器,用于判断用户需要访问的资源与用户所拥有的角色是否匹配  
  16.  * @author Keven  
  17.  *  
  18.  */   
  19. public   class  SecurityAccessDecisionManager  implements  AccessDecisionManager {  
  20.   
  21.     @Override   
  22.     public   void  decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)  throws  AccessDeniedException, InsufficientAuthenticationException {  
  23.         if (configAttributes ==  null )  
  24.             return ;  
  25.         //获取资源与角色对应关系列表   
  26.         Iterator<ConfigAttribute> iter = configAttributes.iterator();  
  27.         while (iter.hasNext()) {  
  28.             ConfigAttribute configAttribute = iter.next();  
  29.             //获取访问该资源需要的角色   
  30.             String needRole = ((SecurityConfig)configAttribute).getAttribute();  
  31.             //从上下文环境获取用户所具有的角色   
  32.             for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {  
  33.                 //判断用户拥有的角色是否与访问该资源所需要的角色匹配   
  34.                 if (needRole.equals(grantedAuthority.getAuthority()))  
  35.                     return ;  
  36.             }  
  37.         }  
  38.         throw   new  AccessDeniedException( "权限不足!" );  
  39.     }  
  40.   
  41.     @Override   
  42.     public   boolean  supports(ConfigAttribute arg0) {  
  43.         return   true ;  
  44.     }  
  45.   
  46.     @Override   
  47.     public   boolean  supports(Class<?> arg0) {  
  48.         return   true ;  
  49.     }  

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics