2012-06-11 63 views
3

最近我一直在研究spring安全性,我需要知道如何动态地使用数据库来定义intercept-url(在Spring Security中)。Spring Security - 如何使用数据库动态定义拦截URL?

我已经深入了解整个互联网,我找不到任何独特的(当然有用的)教程在这方面。

因此,这里是我做过什么:


首先我实现FilterInvocationSecurityMetadataSource抽象类:

public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { 


    public List<ConfigAttribute> getAttributes(Object object) { 
     FilterInvocation fi = (FilterInvocation) object; 
     String url = fi.getRequestUrl(); 
     List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(); 

     attributes = getAttributesByURL(url); 

     return attributes; 
    } 

    public Collection<ConfigAttribute> getAllConfigAttributes() { 
     return null; 
    } 

    public boolean supports(Class<?> clazz) { 
     return FilterInvocation.class.isAssignableFrom(clazz); 
    } 

    public List<ConfigAttribute> getAttributesByURL(String inputUrl) 
    { 
     List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(); 

     Connection connection = null; 
     String url = "jdbc:mysql://173.0.0.22:3306/"; 
     String dbName = "kheirkhahandb"; 
     String driverName = "com.mysql.jdbc.Driver"; 
     String userName = "kheirkhahan"; 
     String password = "kheirkhahan"; 
     try{ 
      Class.forName(driverName).newInstance(); 
      connection = DriverManager.getConnection(url+dbName, userName, password); 
      try{ 
       Statement stmt = connection.createStatement(); 
       String selectquery = "select * from URL_ACCESS where URL = '" + inputUrl +"'"; 
       ResultSet rs = stmt.executeQuery(selectquery); 
       while(rs.next()){ 
        MyConfigAttribute temp = new MyConfigAttribute(); 
        String attr = rs.getString("ACCESS").toString(); 
        temp.setAttr(attr); 
        attributes.add(temp); 
       } 
      } 
      catch(SQLException s){ 
       System.out.println(s); 
      } 
      connection.close(); 
     } 
     catch (Exception e){ 
      e.printStackTrace(); 
     } 
     return attributes; 
    } 



和设置我的security.xml为:

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> 
     <sec:filter-chain-map path-type="ant"> 
      <sec:filter-chain pattern="/css/**" filters="none" /> 
      <sec:filter-chain pattern="/images/**" filters="none" /> 
      <sec:filter-chain pattern="/login.jsp*" filters="none" /> 
      <sec:filter-chain pattern="/**" 
       filters=" 
      securityContextPersistenceFilter, 
      logoutFilter, 
      authenticationProcessingFilter, 
      exceptionTranslationFilter, 
      filterSecurityInterceptor" /> 
     </sec:filter-chain-map> 
    </bean> 

    <bean id="securityContextPersistenceFilter" 
     class="org.springframework.security.web.context.SecurityContextPersistenceFilter"> 
    </bean> 

    <bean id="exceptionTranslationFilter" 
     class="org.springframework.security.web.access.ExceptionTranslationFilter"> 
     <property name="authenticationEntryPoint" ref="authenticationEntryPoint" /> 
     <property name="accessDeniedHandler" ref="accessDeniedHandler" /> 
    </bean> 

    <bean id="authenticationEntryPoint" 
     class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> 
     <property name="loginFormUrl" value="/login.jsp?error=entryPoint" /> 
    </bean> 

    <bean id="accessDeniedHandler" 
     class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> 
     <property name="errorPage" value="/login.jsp?error=access_denied" /> 
    </bean> 

    <bean id="authenticationProcessingFilter" 
     class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
     <property name="authenticationManager" ref="authenticationManager" /> 
    </bean> 

    <bean id="filterSecurityInterceptor" 
     class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> 
     <property name="authenticationManager" ref="authenticationManager" /> 
     <property name="accessDecisionManager" ref="accessDecisionManager" /> 
     <property name="securityMetadataSource" ref="myFilterInvocationSecurityMetadataSource" /> 
    </bean> 

    <bean id="myFilterInvocationSecurityMetadataSource" class="com.datx.dao.MyFilterSecurityMetadataSource"> 
    </bean> 

    <bean id="logoutFilter" 
     class="org.springframework.security.web.authentication.logout.LogoutFilter"> 
     <constructor-arg value="/login.jsp?error=logout" /> 
     <constructor-arg ref="logoutHandler"> 
     </constructor-arg> 
    </bean> 

    <bean id="logoutHandler" 
     class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"></bean> 
<sec:authentication-manager alias="authenticationManager"> 
     <sec:authentication-provider> 
      <sec:jdbc-user-service data-source-ref="dataSource" 
       group-authorities-by-username-query=" 
             SELECT acg.ID, acg.GROUP_NAME, a.AUTHORITY_NAME AS AUTHORITY 
             FROM ACCESS_GROUPS acg, ACCESS_GROUP_MEMBERSHIP agm, GROUP_AUTHORITIES ga, AUTHORITIES a 
             WHERE agm.USERNAME = ? and acg.ID = ga.GROUP_ID and acg.ID = agm.GROUP_ID and ga.AUTHORITY_ID = a.ID 
            " 
       users-by-username-query="SELECT USERNAME,PASSWORD,IS_ACTIVE FROM USER where USERNAME = ?" 
       authorities-by-username-query=" 
             SELECT ua.USERNAME, a.AUTHORITY_NAME AS AUTHORITY 
             FROM USER_AUTHORITIES ua, AUTHORITIES a 
             WHERE ua.USERNAME = ? and ua.AUTHORITY_ID = a.ID 
            " /> 
     </sec:authentication-provider> 
    </sec:authentication-manager> 

    <bean id="accessDecisionManager" 
     class="org.springframework.security.access.vote.AffirmativeBased"> 
     <property name="decisionVoters"> 
      <list> 
       <ref bean="roleVoter" /> 
      </list> 
     </property> 
    </bean> 
    <bean id="roleVoter" 
     class="org.springframework.security.access.vote.RoleHierarchyVoter"> 
     <property name="rolePrefix" value="" /> 
     <constructor-arg ref="roleHierarchy" /> 
    </bean> 

<bean id="roleHierarchy" class="com.datx.dao.MyRoleHierarchyImpl"> 
     <property name="roleHierarchyEntryDaoJdbc" ref="RoleHierarchyEntryDaoJdbc" /> 
    </bean> 

</beans> 



有一些问题,我找不到:
1.我已经在URL_ACCESS数据库中插入了一些对,如“URL”,“ROLE”> <。但我不知道getAttributes方法是否工作正常与否
2.我一定要实现所有这些,我在



3使用的过滤器。当用户使用错误的用户名/密码或尝试访问不允许的页面时,我收到异常,而不是被重定向到login.jsp。这是为什么?

在此先感谢

+0

我不确定你为什么要这样做。您的应用程序是否如此动态,以至于在使用需要拦截的应用程序时会创建新的url。我通常不会在数据库中放入任何东西,只会随着新版本的发展而变化,从而导致新的版本。 – tom

回答

2

谢谢Tom和Rob的快速回复。

首先,我完全意识到“在数据库中存储url模式不是一个好主意”。但是,我们正在尝试动态管理所有内容。所以没有其他选择。

事实证明,我的代码有一些小问题。 在这里,我会逐一回答每个问题。

  1. 我的getAttributes方法工作得很好。但是有一种替代方法来加载网址模式。 我可以单独加载所有的url模式及其相应的角色到一个HashedMap中。而在getAttributes方法中,我可以只查找HasehdMap。 简言之,这将会是这样的:

    • HashedMap URL的访问 = myDBManager.getAllUrlAccess();
      而在我的getAttributes方法中,我使用这个url-access的东西。
  2. 问题以某种方式修剪! 我想了解springSecurityFilterChain bean中使用的那些过滤器。

    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> 
         <security:filter-chain-map path-type="ant"> 
          <sec:filter-chain pattern="/css/**" filters="none" /> 
          <sec:filter-chain pattern="/images/**" filters="none" /> 
          <sec:filter-chain pattern="/login.jsp*" filters="none" /> 
          <sec:filter-chain pattern="/**" 
           filters=" 
          securityContextPersistenceFilter, 
          logoutFilter, 
          authenticationProcessingFilter, 
          exceptionTranslationFilter, 
          filterSecurityInterceptor" /> 
         </security:filter-chain-map> 
    </bean> 
    
  3. 我收到了异常,因为在authenticationProcessingFilter豆有没有这样的特性。 所以我把它再这样写:

    <bean id="authenticationProcessingFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
        <property name="authenticationFailureHandler" ref="authenticationFailureHandler" /> 
        <property name="filterProcessesUrl" value="/j_spring_security_check" /> 
        <property name="usernameParameter" value="j_username" /> 
        <property name="passwordParameter" value="j_password" /> 
        <property name="authenticationManager" ref="authenticationManager" /> 
    </bean> 
    

,当然我已经向大家介绍authenticationFailureHandler豆这个问题,以及:

<bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> 
     <property name="defaultFailureUrl" value="/index.jsp" /> 
</bean> 

现在我没有收到任何异常。

但是这里出现了另一个问题: 我不明白用户名/密码是不正确还是用户名无法访问请求的页面。 在这两种情况下,用户按照这个bean重定向:

<bean id="authenticationEntryPoint" 
    class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> 
     <property name="loginFormUrl" value="/login.jsp?error=EntryPoint" /> 
</bean> 

为什么控制这两种情况?

+0

你有解决这个问题吗? – OscarG

+0

是的。我现在有两个不同的类,用于“拒绝访问”和“入口点”。对于前者,我抛出一个'403'异常,对于后者,用户被重定向到页面。我所要做的就是使用另一个“拒绝访问的异常处理程序”,并通过我们的UI处理'403'响应。 –

4

首先,我会确保你已咨询FAQ这个保证你真的想这样做。正如tom所暗示的,通常不建议将这些信息放入数据库中。

就目前的代码是否工作而言,很难说没有更多细节。例如,您在日志中看到的错误是什么? #2中的问题似乎并不完整。 Spring Security日志说了什么?

如果要坚持这个计划,我会继续充分使用命名空间配置和leverage a BeanPostProcessor (as discussed on the FAQ)来换出FilterInvocationServiceSecurityMetadataSource。实现可能是这个样子:

public class FilterInvocationServiceSecurityMetadataSourceBeanPostProcessor 
    implements BeanPostProcessor { 
    private FilterInvocationServiceSecurityMetadataSource metadataSource; 

    public void setMetadataSource(FilterInvocationServiceSecurityMetadataSource metadataSource) { 
     this.metadataSource = metadataSource; 
    } 

    public Object postProcessBeforeInitialization(Object bean, String beanName) { 
     if(bean instanceof FilterInvocationSecurityMetadataSource) { 
      return metadataSource; 
     } 
     return bean; 
    } 

    public Object postProcessAfterInitialization(Object bean, String beanName) { 
     return bean; 
    } 
} 

然后自定义FilterInvocationServiceSecurityMetadataSource可以在Spring配置与FilterInvocationServiceSecurityMetadataSourceBeanPostProcessor一起指定。

<bean id="fiMds" class="FilterInvocationServiceSecurityMetadataSourceBeanPostProcessor"> 
    <property name="metadataSource"> 
    <bean id="myFilterInvocationSecurityMetadataSource" class="com.datx.dao.MyFilterSecurityMetadataSource"/> 
    </property> 
</bean> 
相关问题