spring security リクエスト毎に認証処理を実施する方法

spring

Spring Securityの認証処理は基本ログイン時に一度だけ実行されます。しかしリクエスト毎にセッションやCookieをチェックしたいというようなケースもあるかと思います。

そんな時はSessionManagementFilterを使えばリクエスト毎に必要な認証処理を入れることができます。

[スポンサーリンク]

はじめに

リクエスト毎に認証処理を入れる方法の解説ですが、以前紹介しました認証処理を自作する方法をベースに解説を進めてきます。

こちらページ内のサンプルコードへ今回紹介する部分を追加することで、リクエスト毎に走る認証処理を実現していきます。

Spring Securityの設定ファイル

SESSION_MANAGEMENT_FILTERでリクエスト毎に走るfilterをセットします。

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

    <!-- 自作の認証を使う場合は、entry-point-refを指定します。 --> 
    <http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint" >

        <!-- 自作の認証filterを指定します。 --> 
        <custom-filter after="FORM_LOGIN_FILTER" ref="customLoginFilter" />
        <session-management session-fixation-protection="none" />
        <custom-filter after="SESSION_MANAGEMENT_FILTER" ref="customSessionManagementFilter"/>

        <intercept-url pattern="/top*" access="hasAnyRole('ROLE_ADMIN', 'ROLE_USER')" />
        <intercept-url pattern="/admin*" access="hasRole('ROLE_ADMIN')" />
        <intercept-url pattern="/user*" access="hasRole('ROLE_USER')" />

        <access-denied-handler error-page="/403" />
        
        <!-- 認証のログイン処理は、自作認証を使う場合は不要です。 -->
        <!-- 
        <form-login 
            login-page="/" 
            default-target-url="/top" 
            authentication-failure-url="/error" 
            login-processing-url="/j_spring_security_check"/>
         -->
         
        <logout
            logout-url="/logout"
            logout-success-url="/"
            invalidate-session="true"/>
        <!-- anonymousユーザのROLE -->
        <anonymous granted-authority="ROLE_ANONYMOUS" />
    </http>

    <!-- Session チェック用のfilterです。 --> 
    <beans:bean id="customSessionManagementFilter"
                  class="jp.co.security.CustomSessionManagementFilter">
        <beans:constructor-arg name="securityContextRepository"
                                 ref="httpSessionSecurityContextRepository" />
    </beans:bean>
    
    <beans:bean id="httpSessionSecurityContextRepository"
                  class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
    
    <!-- entry-point-refは、どのパスへアクセスした時に自作認証filterを実行するのかを指定します。 --> 
    <beans:bean id="loginUrlAuthenticationEntryPoint"
         class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <beans:constructor-arg value="/" />
    </beans:bean>

    <!-- 最初に動く認証filterです。 --> 
    <beans:bean id="customLoginFilter"
        class="jp.co.security.CustomLoginFilter">
        <!-- 次に動くfilterです。ここで認可(ロール)の設定をします。 --> 
        <beans:property name="authenticationManager" ref="authenticationManager" />
        <beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
        <beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
        <beans:property name="filterProcessesUrl" value="/authentication" /> 
    </beans:bean>
    
    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="customAuthenticationProvider" />
    </authentication-manager>
     
    <beans:bean id="customAuthenticationProvider"
        class="jp.co.security.CustomAuthenticationProvider" />
    
    <beans:bean id="authenticationFailureHandler"
        class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler" >
        <beans:property name="defaultFailureUrl" value="/error"/>
        <beans:property name="useForward" value="true"/>
        <beans:property name="exceptionMappings">
            <beans:props>
              <beans:prop key=
                "org.springframework.security.authentication.AuthenticationServiceException">
                  /error
              </beans:prop>
            </beans:props>
        </beans:property>

    </beans:bean>
        
    <beans:bean id="authenticationSuccessHandler"
        class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler" >
        <beans:property name="targetUrlParameter" value="redirectTo"/> 
    </beans:bean>

</beans:beans>

Sessionチェック用のfilter

Sessionチェック用となっていますが、Requestオブジェクト内の値(Cookieなど)何でもチェックできます。
もちろんこのクラス内でDBへ接続することも可能です。

public class CustomSessionManagementFilter extends SessionManagementFilter {

    public CustomSessionManagementFilter(
            SecurityContextRepository securityContextRepository) {
        super(securityContextRepository);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        System.out.println("リクエスト毎に実行されます。");
        chain.doFilter(request, response);
    }
}

springとjavaのバージョン

springframeworknのバージョンは、4.0.1を使っています。
javaは、version 8を使っています。

さいごに

わたしの経験上、大規模な商用システムともなると、初回の認証処理だけではなくリクエスト毎にセッションやCookieの値をチェックするというシステムが多かったように感じます。

認証処理が初回ログイン時だけで終わるというのが稀な気がします。

Spring Securityではこのあたりもサポートしてくれるので嬉しいですね。

それでは!