• [转]Spring Security 可动态授权RBAC权限模块实践


    RBAC:基于角色的访问控制(Role-Based Access Control)

    先在web.xml 中配置一个过滤器(必须在Struts的过滤器之前)

    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解析的路径下


    Spring Security主要做两件事,一件是认证,一件是授权。


    认证

    当用户访问受保护的信息却没有登录获得认证时,框架会自动将请求跳转到登录页面


    在http标签中的

    1. <form-login login-page="/page/login.jsp" />  


    配置。且该登录页面必须是不被拦截的。故要配置上

    1. <intercept-url pattern="/page/login.jsp" filters="none" />  



    Web项目的认证如果在HTTP标签中配置了auto-config="true",框架就会自动的配置多8?个拦截器。 默认表单登录认证的是FORM_LOGIN_FILTER拦截器,我们可以直接写自定义的UserDetailsService,在这个类中实现方法 UserDetails loadUserByUsername(String username),从数据库获取用户信息以及其拥有的角色

    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. }  

    配置在

    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标签中加入

    1. <custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER" />  


    并配置

    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 类是这么写的

    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中在默认授权拦截器前配置了自定义的拦截器

    1. <custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" />  


    本平台采用基于请求URL地址的验证方式


    securityFilter的配置如下

    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
    采用投票者来判断是否授权。

    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匹配模式,所需要角色的集合。

    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配置文件

      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
  • 相关阅读:
    WPF Margin和Padding
    WPF Tab切换顺序设置
    WPF DataGrid DataGridTemplateColumn
    WPF CheckBox IsHitTestVisible
    WPF Tag
    WPF RadioButton
    WPF 用户控件(UserControl)
    WPF ToolTip
    Style Lessons in Clarity and Grace (11th Edition)中文翻译
    AI for AI
  • 原文地址:https://www.cnblogs.com/ZhuRenWang/p/4773189.html
Copyright © 2020-2023  润新知