[轉]Spring Security 可動態受權RBAC權限模塊實踐

RBAC:基於角色的訪問控制(Role-Based Access Control)

先在web.xml 中配置一個過濾器(必須在Struts的過濾器以前)css

[html] view plain copy
  1. <filter>  
  2.     <filter-name>springSecurityFilterChain</filter-name>  
  3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  4. </filter>  
  5. <filter-mapping>  
  6.     <filter-name>springSecurityFilterChain</filter-name>  
  7.     <url-pattern>/*</url-pattern>  
  8. </filter-mapping>  

 

而後就是編寫Spring安全的配置文件applicationContext-security.xml並配置到Spring解析的路徑下html


Spring Security主要作兩件事,一件是認證,一件是受權。java


認證
web

當用戶訪問受保護的信息卻沒有登陸得到認證時,框架會自動將請求跳轉到登陸頁面


在http標籤中的spring

[html] view plain copy
  1. <form-login login-page="/page/login.jsp" />  


配置。且該登陸頁面必須是不被攔截的。故要配置上數據庫

[html] view plain copy
  1. <intercept-url pattern="/page/login.jsp" filters="none" />  



Web項目的認證若是在HTTP標籤中配置了auto-config="true",框架就會自動的配置多8?個攔截器。 默認表單登陸認證的是FORM_LOGIN_FILTER攔截器,咱們能夠直接寫自定義的UserDetailsService,在這個類中實現方法 UserDetails loadUserByUsername(String username),從數據庫獲取用戶信息以及其擁有的角色緩存

[java] view plain copy
  1. @Service("myUserDetailsService")  
  2. public class MyUserDetailsServiceImpl extends BaseService implements UserDetailsService {  
  3. @Resource  
  4. private UserDao userDao;  
  5.   
  6.   
  7. public UserDetails loadUserByUsername(String username)  
  8. throws UsernameNotFoundException, DataAccessException {  
  9.   
  10. User user = userDao.getUserByUsername(username);  
  11. List<Role> roles = user.getRoles();  
  12. Collection<GrantedAuthority> authorities = new LinkedList<GrantedAuthority>();  
  13.   
  14. for (Role role : roles) {  
  15. authorities.add(new GrantedAuthorityImpl(role.getCode()));  
  16. }  
  17.   
  18. UserDetails userDetails = new org.springframework.security.core.userdetails.User(username,user.getPassword(),Constants.STATE_VALID.equals(user.getState()),true,true,true,authorities);  
  19.   
  20. return userDetails;  
  21. }  
  22.   
  23.   
  24. }  

 

配置在安全

[html] view plain copy
  1. <authentication-manager alias="myAuthenticationManager">  
  2.     <authentication-provider user-service-ref="myUserDetailsService">  
  3.         <password-encoder hash="md5" />  
  4.     </authentication-provider>  
  5. </authentication-manager>  


若是須要在登陸的時候,在HTTP SESSION中配置作些操做的。就得配置自定義的FORM_LOGIN_FILTER了 在HTTP標籤中加入session

[html] view plain copy
  1. <custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER" />  


並配置app

[html] view plain copy
  1. <!-- 訪問控制驗證器Authority -->  
  2. <beans:bean id="securityFilter"  
  3. class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">  
  4. <beans:property name="authenticationManager" ref="myAuthenticationManager" />  
  5. <beans:property name="accessDecisionManager"  
  6. ref="affirmativeBasedAccessDecisionManager" />  
  7. <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"/>  
  8. </beans:bean>  




MyUsernamePasswordAuthenticationFilter 類是這麼寫的

[java] view plain copy
  1. public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{  
  2. public static final String USERNAME = "username";  
  3. public static final String PASSWORD = "password";  
  4.   
  5. @Resource  
  6. private LoginService loginService;  
  7. private UserLoginFormBean userLoginFormBean = new UserLoginFormBean();  
  8.   
  9. @Resource  
  10. private LogService logService;  
  11.   
  12.   
  13.   
  14. @Override  
  15. public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {  
  16. String username = obtainUsername(request);  
  17. String password = obtainPassword(request);  
  18.   
  19. HttpSession session = request.getSession();  
  20.   
  21. userLoginFormBean.setUsername(obtainUsername(request));  
  22. userLoginFormBean.setPassword(obtainPassword(request));  
  23.   
  24. User user = loginService.login(userLoginFormBean);  
  25. session.setAttribute(Constants.SESSION_USER, user);  
  26.   
  27.   
  28. Log log = new Log(user,getIpAddr(request),"用戶登陸", null);  
  29. logService.add(log);  
  30.   
  31. //UsernamePasswordAuthenticationToken實現 Authentication  
  32. UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);  
  33. // Place the last username attempted into HttpSession for views  
  34.   
  35. // 容許子類設置詳細屬性  
  36.         setDetails(request, authRequest);  
  37.   
  38.         // 運行UserDetailsService的loadUserByUsername 再次封裝Authentication  
  39. return this.getAuthenticationManager().authenticate(authRequest);  
  40. }  
  41.   
  42.   
  43.   
  44. }  


getAuthenticationManager().authenticate(authRequest)是爲了讓UserDetailService提供Detailed的信息並認證

受權

在受權時,系統默認經過FILTER_SECURITY_INTERCEPTOR認證。


如需自定義受權攔截器,咱們在HTTP中在默認受權攔截器前配置了自定義的攔截器

[html] view plain copy
  1. <custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" />  


本平臺採用基於請求URL地址的驗證方式


securityFilter的配置以下

[html] view plain copy
  1. <!-- 訪問控制驗證器Authority -->  
  2. <beans:bean id="securityFilter"  
  3.     class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">  
  4.     <beans:property name="authenticationManager" ref="myAuthenticationManager" />  
  5.     <beans:property name="accessDecisionManager"  
  6.         ref="affirmativeBasedAccessDecisionManager" />  
  7.     <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"/>  
  8. </beans:bean>  



採用默認的自定義的也是採用Spring默認的FilterSecurityInterceptor攔截器,accessDecisionManager也採用的是框架提供的affirmativeBasedAccessDecisionManager
採用投票者來判斷是否受權。

[html] view plain copy
  1. <beans:bean id="affirmativeBasedAccessDecisionManager"  
  2.         class="org.springframework.security.access.vote.AffirmativeBased">  
  3.         <beans:property name="decisionVoters" ref="roleDecisionVoter" />  
  4.     </beans:bean>  
  5.       
  6.     <beans:bean name="roleDecisionVoter"  
  7.         class="org.springframework.security.access.vote.RoleVoter" />  
  8.           
  9. <beans:bean id="mySecurityMetadataSource"  
  10.         class="org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource">  
  11.         <beans:constructor-arg  
  12.             type="org.springframework.security.web.util.UrlMatcher" ref="antUrlPathMatcher" />  
  13.         <beans:constructor-arg type="java.util.LinkedHashMap"  
  14.             ref="securityRequestMapFactoryBean" />  
  15. </beans:bean>  



SecurityMetadataSource也是ss web框架提供的DefaultFilterInvocationSecurityMetadataSource,只是初始化參數中,一個選擇 antUrl匹配,仍是正則匹配,另外一個是提供自定義的經過securityRequestMapFactoryBean。在後者是一個 LinkedHashMap<RequestKey, Collection<ConfigAttribute>>類型,就是每個URL匹配模式,所須要角色的集合。

[java] view plain copy
  1. @Service("securityRequestMapFactoryBean")  
  2. public class SecurityRequestMapFactoryBean extends  
  3.         LinkedHashMap<RequestKey, Collection<ConfigAttribute>> {  
  4.       
  5.     @Resource  
  6.     private ModuleDao moduleDao;  
  7.       
  8.     @PostConstruct  
  9.     public void loadSecurityInfos(){  
  10.         List<Module> modules = moduleDao.getAll(new Module());  
  11. //      List<Role> roles = roleDao.getAll(new Role());  
  12.         for (Module module : modules) {  
  13.             RequestKey requestKey = new RequestKey(module.getPageUrl());  
  14.             Collection<ConfigAttribute> configAttributes = new LinkedList<ConfigAttribute>();  
  15.             for (final Role role : module.getRoles()) {  
  16.                 configAttributes.add(new ConfigAttribute() {  
  17.                     public String getAttribute() {  
  18.                         return role.getCode();  
  19.                     }  
  20.                 });  
  21.             }  
  22.             this.put(requestKey, configAttributes);  
  23.         }  
  24.     }  
  25.       
  26. }  


PS: 最終的件applicationContext-security.xml配置文件

[html] view plain copy
    1. <pre name="code" class="html"><?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" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    5.                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">  
    6.   
    7.     <http auto-config="true">  
    8.         <intercept-url pattern="/page/login.jsp" filters="none" />  
    9.         <intercept-url pattern="/LoginAction*" filters="none" />  
    10.         <intercept-url pattern="/common/**" filters="none" />  
    11.         <intercept-url pattern="/css/**" filters="none" />  
    12.         <intercept-url pattern="/common/**" filters="none" />  
    13.         <intercept-url pattern="/images/**" filters="none" />  
    14.         <intercept-url pattern="/js/**" filters="none" />  
    15.   
    16.         <form-login login-page="/page/login.jsp" />  
    17.         <custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER" />  
    18.         <custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" />  
    19.     </http>  
    20.   
    21.     <!-- 訪問控制驗證器Authority -->  
    22.     <beans:bean id="securityFilter"  
    23.         class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">  
    24.         <beans:property name="authenticationManager" ref="myAuthenticationManager" />  
    25.         <beans:property name="accessDecisionManager"  
    26.             ref="affirmativeBasedAccessDecisionManager" />  
    27.         <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"/>  
    28.     </beans:bean>  
    29.   
    30.     <!-- 登陸驗證器Authentication -->  
    31.     <beans:bean id="loginFilter"  
    32.         class="com.epro.crm.util.security.MyUsernamePasswordAuthenticationFilter">  
    33.         <!-- 處理登陸的action -->  
    34.         <beans:property name="filterProcessesUrl" value="/SecurityCheck" />  
    35.         <!-- 驗證成功後的處理-->  
    36.         <beans:property name="authenticationSuccessHandler"  
    37.             ref="loginLogAuthenticationSuccessHandler" />  
    38.         <!-- 驗證失敗後的處理-->  
    39.         <beans:property name="authenticationFailureHandler"  
    40.             ref="simpleUrlAuthenticationFailureHandler" />  
    41.         <beans:property name="authenticationManager" ref="myAuthenticationManager" />  
    42.         <!-- 注入DAO爲了查詢相應的用戶 -->  
    43.         <beans:property name="loginService" ref="loginService" />  
    44.         <beans:property name="logService" ref="logService" />  
    45.     </beans:bean>  
    46.   
    47.     <authentication-manager alias="myAuthenticationManager">  
    48.         <authentication-provider user-service-ref="myUserDetailsService">  
    49.             <password-encoder hash="md5" />  
    50.         </authentication-provider>  
    51.     </authentication-manager>  
    52.   
    53.     <beans:bean id="mySecurityMetadataSource"  
    54.         class="org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource">  
    55.         <beans:constructor-arg  
    56.             type="org.springframework.security.web.util.UrlMatcher" ref="antUrlPathMatcher" />  
    57.         <beans:constructor-arg type="java.util.LinkedHashMap"  
    58.             ref="securityRequestMapFactoryBean" />  
    59.     </beans:bean>  
    60.   
    61.     <beans:bean id="antUrlPathMatcher"  
    62.         class="org.springframework.security.web.util.AntUrlPathMatcher" />  
    63.           
    64.     <beans:bean id="affirmativeBasedAccessDecisionManager"  
    65.         class="org.springframework.security.access.vote.AffirmativeBased">  
    66.         <beans:property name="decisionVoters" ref="roleDecisionVoter" />  
    67.     </beans:bean>  
    68.   
    69.     <beans:bean name="roleDecisionVoter"  
    70.         class="org.springframework.security.access.vote.RoleVoter" />  
    71.   
    72.     <beans:bean id="loginLogAuthenticationSuccessHandler"  
    73.         class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">  
    74.         <beans:property name="defaultTargetUrl" value="/page/main.jsp"></beans:property>  
    75.     </beans:bean>  
    76.   
    77.     <beans:bean id="simpleUrlAuthenticationFailureHandler"  
    78.         class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">  
    79.         <!-- 
    80.             能夠配置相應的跳轉方式。屬性forwardToDestination爲true採用forward false爲sendRedirect 
    81.         -->  
    82.         <beans:property name="defaultFailureUrl" value="/page/login.jsp"></beans:property>  
    83.     </beans:bean>  
    84.   
    85.     <!-- 未登陸的切入點 -->  
    86.     <beans:bean id="authenticationProcessingFilterEntryPoint"  
    87.         class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  
    88.         <beans:property name="loginFormUrl" value="/page/login.jsp"></beans:property>  
    89.     </beans:bean>  
    90.   
    91. </beans:beans></pre><br>  
    92. ------------------------------------------------------ 分割線 -----------------------------------------------------------------<br>  
    93. <br>  
    94. 後記:  
    95. <pre></pre>  
    96. 因爲權限配置信息,是由初始化mySecurityMetadataSource時,就由mySecurityMetadataSource讀取提供的權限信息,並緩存與該類的私有成員變量中,因此從新加載時就須要從新新建一個對象  
    97. <pre></pre>  
    98. <pre name="code" class="java">public void loadSecurityInfos(){  
    99.         this.clear();  
    100.         List<Modulemodules = moduleDao.getAll(new Module());  
    101.         Collections.sort(modules);  
    102.         for (Module module : modules) {  
    103.             RequestKey requestKey = new RequestKey(module.getPageUrl());  
    104.             Collection<ConfigAttributeconfigAttributes = new LinkedList<ConfigAttribute>();  
    105.             moduleDao.refresh(module);  
    106.             List<Roleroles = module.getRoles();  
    107.             if(roles != null){  
    108.                 for (final Role role : roles) {  
    109.                     configAttributes.add(new ConfigAttribute() {  
    110.                         public String getAttribute() {  
    111.                             return role.getCode();  
    112.                         }  
    113.                     });  
    114.                 }  
    115.             }  
    116.               
    117.             this.put(requestKey, configAttributes);  
    118.             log.info(module.getName()+ "模塊 URL模式:" + requestKey + " 受權角色:"+ roles);  
    119.         }  
    120.     }</pre><br>  
    121. <br>  
    122. <pre></pre>  
    123. <pre></pre>  
    124. <pre></pre>  
    125. <pre></pre>  
    126. <pre></pre>  
    127. <pre></pre>  
    128. <pre></pre>  
    129. <pre></pre>  
    130. <pre></pre>  
    131. <pre></pre>  
    132. <pre></pre>  
    133.       
    134.         <div style="padding-top:20px">           
    135.             <style="font-size:12px;">版權聲明:本文爲博主原創文章,未經博主容許不得轉載。</p>  
    136.         </div
相關文章
相關標籤/搜索