web-dev-qa-db-ja.com

REST Spring 3でのログイン/ログアウト

私たちは、Spring 3でRESTful Webサービスを開発しており、/webservices/login/<username>/<password>//webservices/logoutのような、ログイン/ログアウトの機能が必要です。セッションは、他のWebサービスの使用を許可するために、セッションがタイムアウトまたはログアウトするまでコンテキストに保存する必要があります。セッション情報のないWebサービスへのアクセス要求はすべて拒否する必要があります。このシナリオのための最先端のソリューションを探しています。

私は実際にここで尋ねられた質問を復活させています Spring Security 3プログラムでログイン 、これはまだ適切に回答されていません。必要な変更をweb.xmlにも指定してください。

21
FKhan

Spring Securityフィルターを完全に手動で定義することをお勧めします。それはそれほど難しくなく、ログイン/ログアウトの動作を完全に制御できます。

最初に、フィルターチェーンの処理をSpringに委任するには、標準のweb.xmlの宣伝文句が必要です(サーブレットAPIバージョン3を使用していない場合は、非同期サポートを削除してください)。

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <async-supported>true</async-supported>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>



<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

ここで、セキュリティコンテキストで、各パスに個別にフィルターを定義します。フィルターは、ユーザーの認証、ユーザーのログアウト、セキュリティ資格情報の確認などを行うことができます。

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <sec:filter-chain-map path-type="ant">
        <sec:filter-chain pattern="/login" filters="sif,wsFilter"/>
        <sec:filter-chain pattern="/logout" filters="sif,logoutFilter" />
        <sec:filter-chain pattern="/rest/**" filters="sif,fsi"/>
    </sec:filter-chain-map>
</bean>

上記のXMLは、フィルターチェーンを通じて特定のコンテキスト相対URLにリクエストを渡すようにSpringに指示します。フィルターチェーンの最初のことは、セキュリティコンテキストの確立です-'sif' Beanがそれを処理します。

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

チェーンの次のフィルターは、データをセキュリティコンテキスト(読み取り:ユーザーのログイン/ログアウト)に追加するか、またはこのセキュリティコンテキストに基づいてアクセスを許可するかどうかを決定できます。

ログインURLについては、リクエストから認証データを読み取り、それを検証し、次にセキュリティコンテキスト(セッションに保存されている)に保存するフィルターが必要になります。

<bean id="wsFilter" class="my.own.security.AuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="authenticationSuccessHandler" ref="myAuthSuccessHandler"/>
  <property name="passwordParameter" value="pass"></property>
  <property name="usernameParameter" value="user"></property>
  <property name="postOnly" value="false"></property>

SpringジェネリックUsernamePasswordAuthenticationFilterを使用できますが、私が独自の実装を使用する理由は、フィルターチェーン処理を続行するためです(デフォルトの実装は、ユーザーが認証が成功するとリダイレクトされ、フィルターチェーンを終了することを前提としています)、毎回認証を処理できるようにしますユーザー名とパスワードがそれに渡されます:

public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
    return ( StringUtils.hasText(obtainUsername(request)) && StringUtils.hasText(obtainPassword(request)) );
}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
        Authentication authResult) throws IOException, ServletException{
    super.successfulAuthentication(request, response, chain, authResult);
    chain.doFilter(request, response);
}

/ loginパスの独自のフィルター実装をいくつでも追加できます。たとえば、HTTP基本認証ヘッダー、ダイジェストヘッダーを使用した認証、またはリクエスト本文からのユーザー名/ pwdの抽出などです。 Springはそのためのたくさんのフィルターを提供します。

デフォルトのリダイレクト戦略をオーバーライドする独自の認証成功ハンドラーがあります。

public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

   @PostConstruct
   public void afterPropertiesSet() {
       setRedirectStrategy(new NoRedirectStrategy());
   }

    protected class NoRedirectStrategy implements RedirectStrategy {

        @Override
        public void sendRedirect(HttpServletRequest request,
                HttpServletResponse response, String url) throws IOException {
            // no redirect

        }

    }

}

ログイン成功後にユーザーがリダイレクトされることに問題がなければ、カスタム認証成功ハンドラー(およびおそらくカスタム認証フィルターも)を持つ必要はありません(リダイレクトURLはカスタマイズできます。ドキュメントを確認してください)

ユーザーの詳細の取得を担当する認証マネージャーを定義します。

<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider ref="myAuthAuthProvider"/>
</sec:authentication-manager>

 <bean id="myAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="myUserDetailsImpl"/>
        </bean>
    </property>
</bean>

ここで、独自のユーザー詳細Bean実装を提供する必要があります。

ログアウトフィルター:セキュリティコンテキストのクリアを担当

<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
        </list>
    </constructor-arg>
</bean>

一般的な認証のもの:

<bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <property name="allowIfAllAbstainDecisions" value="false"/>
    <property name="decisionVoters">
        <list>
            <ref bean="roleVoter"/>
        </list>
    </property>
</bean>

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>

<bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>

アクセス制御フィルター(説明が必要です):

<bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="myAuthenticationManager"/>
    <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
    <property name="securityMetadataSource">
        <sec:filter-invocation-definition-source>
            <sec:intercept-url pattern="/rest/**" access="ROLE_REST"/>
        </sec:filter-invocation-definition-source>
    </property>
</bean>

また、メソッドに@Securedアノテーションを付けてRESTサービスを保護することもできます。

上記のコンテキストは、既存のREST service webappから抜粋したものです。タイプミスの可能性があります。

また、ストックsec Springタグを使用して、ここで実装されていることの少なくともほとんどを行うこともできますが、カスタムコントロールを使用することをお勧めします。

これで少なくともあなたが始められることを願っています。

50
rootkit