4

私は最近春のセキュリティに取り組んでおり、データベースを使用して動的にインターセプト URL (Spring Security で) を定義する方法を知る必要があります。

私はすでにインターネット全体を深く掘り下げましたが、この分野でユニークな (そしてもちろん役に立つ) チュートリアルを見つけることができませんでした。

だからここに私がしたことがあります:


まず、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" , "ROLE"> のようないくつかのペアを URL_ACCESS データベースに挿入しました。しかし、getAttributes メソッドが正常に機能しているかどうかはわかりません
2. で使用したすべてのフィルターを実装する必要がありますか?



3. ユーザーが間違ったユーザー名/パスワードを使用したり、許可されていないページにアクセスしようとすると、login.jsp にリダイレクトされずに例外が発生します。何故ですか?

前もって感謝します

4

2 に答える 2

4

まず、これについてよくある質問を参照して、本当にこれをやりたいかどうかを確認してください。トムがほのめかしたように、そのような情報をデータベースに置くことは一般的にお勧めできません。

現在のコードが機能しているかどうか、またはその理由については、詳細なしで言うのは困難です。たとえば、ログに表示されているエラーは何ですか? #2の質問は完全ではないようです。Spring Security ログは何を示していますか?

この計画に固執する場合は、引き続き名前空間構成を完全に使用し、(FAQ で説明されているように) BeanPostProcessor を活用して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; 
    } 
}

次に、FilterInvocationServiceSecurityMetadataSourceSpring 構成でカスタムを .xml と共に指定できますFilterInvocationServiceSecurityMetadataSourceBeanPostProcessor

<bean id="fiMds" class="FilterInvocationServiceSecurityMetadataSourceBeanPostProcessor">
  <property name="metadataSource">
    <bean id="myFilterInvocationSecurityMetadataSource" class="com.datx.dao.MyFilterSecurityMetadataSource"/>
  </property>
</bean>
于 2012-06-11T15:47:37.023 に答える
2

Tom と Rob の両方に迅速な返信をありがとう。

まず第一に、「URL パターンをデータベースに保存するのは得策ではない」ということは十分承知しています。ただし、すべてを動的に管理しようとしています。したがって、他の選択肢はありません。

結局のところ、私のコードには小さな問題がいくつかありました。ここでは、私の質問に 1 つずつお答えします。

  1. 私の getAttributes メソッドは問題なく動作しています。しかし、url-patterns をロードする別の方法があります。最初に、すべての URL パターンとそれに対応するロールを個別に HashedMap に読み込むことができました。getAttributes メソッドでは、代わりに HasehdMap を検索できます。簡単に言えば、次のようになります。

    • HashedMap url-access = 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 にはそのようなプロパティがなかったため、例外を受け取っていました。そこで、次のように書き直します。

    <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 に導入する必要がありました。

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

両方のケースを制御しているのはなぜですか?

于 2012-06-16T07:36:18.980 に答える