今までの記事ではSpringSecurityをそのまま改造せずに使用する方法を見てきました。
ここでは、独自の機能をつける方法を見てみましょう。
【SpringSecurityがどのように動作しているか?】
まず、SpringSecurityがどのように動作しているかを理解しましょう。
SpringSecurityはtomcatのフィルタとして実装されています。
ですので、設定の記事でみたようにweb.xmlに設定します。
web.xmlで設定するフィルタは1つですが、実は内部でさらに複数のフィルタを持っています。
そして実施される順序が決まっています。
eclipseのコンソールウィンドウなどでみると順番が出力されますので参考までに見てみてください。
注目すべきはフィルタのクラス名です。
<出力例>
Filter chain...
[0] - org.springframework.security.context.HttpSessionContextIntegrationFilter[ order=200; ]
[1] - org.springframework.security.ui.logout.LogoutFilter[ order=300; ]
[2] - org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]
[3] - org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter[ order=1100; ]
[4] - org.springframework.security.providers.anonymous.AnonymousProcessingFilter[ order=1300; ]
[5] - org.springframework.security.ui.ExceptionTranslationFilter[ order=1400; ]
[6] - org.springframework.security.ui.SessionFixationProtectionFilter[ order=1600; ]
[7] - org.springframework.security.intercept.web.FilterSecurityInterceptor@b43af3
Checking whether login URL '/login.jsp' is accessible with your configuration
上記の順番で実行されることを覚えておきましょう。
【フィルタの動作】
<フィルタとその動作>
属性名 | 概要 |
---|---|
HttpSessionContextIntegrationFilter | SecurtyContextオブジェクトをセッションオブジェクトに設定するフィルタ。 |
LogoutFilter | logout-urlに設定したURLにアクセスに来たかを調べ、URLがマッチした場合はログアウト処理をするフィルタ。 SecurityContextクラスに設定されているAnthenticationオブジェクトを初期化します。 |
AuthenticationProcessingFilter | 認証を行い、Anthenticationオブジェクト を初期化し、SecurityContextクラスに設定します。 |
SecurityContextHolderAwareRequestFilter | 渡ってくるHttpServletRequestをラップして、ラップしたRequestを次のフィルタに渡すフィルタです。 ラップを実施しているクラスはSavedRequestAwareWrapperです。 |
AnonymousProcessingFilter | Anonymousを許す設定のときに、Authnticationオブジェクト
を作成し、SecurityContextに設定するフィルタ。
このとき作るAuthenticationは、AnonymousAuthenticationTokenクラスです。 |
ExceptionTranslationFilter | これ以後に実行されるフィルタの例外を捕捉するフィルタ。 |
SessionFixationProtectionFilter | 今回のリクエストについて、ユーザが認証されているかを調べ、新しいセッションを開始するフィルタです。 SpringSecurityの同時セッション管理を使用したときの問題を防ぐためのフィルタのようです。 |
FilterSecurityInterceptor | URLのパス名での認可を行うフィルタ。 |
【機能拡張例】
まず自分がしたいことを確認してみましょう!
それがどのフィルタで実行されるべき機能なのかを確認して、
そのクラスを拡張します。
ここでは、認証時に独自の認証をする場合を考えてみます。
独自の認証は、SOAP通信で行う場合などが考えられると思いますが、
機能拡張の例としてとらえて、応用していろいろ拡張をしてみてください。
<拡張するクラスを決める>
ここでは認証時の処理ですので、AuthenticationProcessingFilterが適切と思われます。
SpringSecurityのソースファイルからこのクラスを探して中身を見てみます。
すると、attemptAuthenticationが実際に認証を行っている処理と分かります。
他にもオーバーライドできそうなメソッド(例えば、onPreAuthenticationなど)があるので、それは必要に応じて使いましょう。
<拡張したクラス例>
public class MyAuthenticationProcessingFilter extends AuthenticationProcessingFilter {
@Override public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException {
//通信処理を入れる。(ここでは省略) // return super.attemptAuthentication(request); }
}
<SpringSecurityファイル設定例>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans
"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
"
xmlns:util="http://www.springframework.org/schema/util
"
xmlns:aop="http://www.springframework.org/schema/aop
"
xmlns:sec="http://www.springframework.org/schema/security
"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.1.xsd
">
<!-- 認可設定(FilterSecurityInterceptorクラス)
-->
<sec:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint"
access-denied-page="/403.jsp" path-type="ant">
<sec:intercept-url pattern="/css/*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<sec:intercept-url pattern="/error.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<sec:intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<sec:intercept-url pattern="/403.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<!-- AuthenticationProcessingに独自フィルタを入れる場合はコメントアウトする -->
<!--sec:form-login login-page="/login.jsp" default-target-url="/top.html" authentication-failure-url="/error.jsp"/>
-->
<sec:logout logout-url="/logout" logout-success-url="/login.jsp" invalidate-session="true"/>
<sec:anonymous granted-authority="ROLE_ANONYMOUS"/>
</sec:http>
<!--
ログインユーザの設定。DaoAuthenticationProviderクラスなどに相当する
-->
<sec:authentication-provider >
<sec:user-service>
<sec:user password="taro" name="taro" authorities="ROLE_ADMIN"/>
</sec:user-service>
</sec:authentication-provider>
<!--
authentication-providerタグで生成された
AuthenticationProviderオブジェクトのエイリアス
-->
<sec:authentication-manager alias="authenticationManagerAlias" />
<!--
エントリポイントの設定 (AuthenticationProcessingに独自フィルタに入れる場合設定する)
-->
<bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
</bean>
<!-- 自作フィルタ。
custom-filterタグでどの位置のデフォルトフィルタと入れ替えるかを指定しないといけない。
Springがフィルタの位置名(エントリポイント)を固定でつけている。
-->
<bean id="myFilter" class="mysecurity.MyAuthenticationProcessingFilter">
<sec:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
<property name="defaultTargetUrl" value="/read_top.html"/>
<property name="authenticationManager" ref="authenticationManagerAlias"/>
<property name="authenticationFailureUrl" value="/error.jsp"/>
</bean>
</beans>
【説明】
以前の記事(・実際に認証と認可をWEBにつけるには? )と比べると、設定ファイルがいろいろ追加されて、いくつかコメントアウトされているのが分かるでしょうか?
<フィルタ実行の順序を指定する方法>
さきほど、フィルタに順番が付けられて、その順番で実行されるということを書きました。
独自機能を追加するには順番の位置を指定すればよく、以下の方法があります。
①指定の位置のフィルタを入れ替える。
②指定の位置の前後に入れる。
上記では①の方法で行っています。
フィルタはSpringで管理されていて、すべて位置名がついています。
設定ファイル上は現れませんが内部に持っているのです。
そして、設定ファイルの下のほうで以下のように設定しています。
<bean id="myFilter" class="mysecurity.MyAuthenticationProcessingFilter">
<sec:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
AUTHENTICATION_PROCESSING_FILTERが位置名です。
ですので、位置名さえ分かれば置き換えは簡単にできます。
②の方法は、sec:custom-filter タグの属性after, beforeを使用します。
<位置名を知る方法>
eclipseで、上記タグのposition=""のダブルクォートの間にカーソルを置いて、
Ctrl+Space キーを押してください。
候補が出てきます。
参考までに記述すると以下の記述ができます。
起動時にコンソールに出力された7つ以上あるのは、設定によって使用されるフィルタが違うからです。
- FIRST
- CHANNEL_FILTER
- CONCURRENT_SESSION_FILTER
- SESSION_CONTEXT_INTEGRATION_FILTER
- LOGOUT_FILTER
- X509_FILTER
- PRE_AUTH_FILTER
- CAS_PROCESSING_FILTER
- AUTHENTICATION_PROCESSING_FILTER
- BASIC_PROCESSING_FILTER
- SERVLET_API_SUPPORT_FILTER
- REMEMBER_ME_FILTER
- ANONYMOUS_FILTER
- EXCEPTION_TRANSLATION_FILTER
- NTLM_FILTER
- FILTER_SECURITY_INTERCEPTOR
- SWITCH_USER_FILTER
- LAST
<認可のフィルタ(authenticationProcessingFilter)の場合>
認可の設定を上の方で行っています。(以下、再掲)
<sec:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint"
access-denied-page="/403.jsp" path-type="ant">
このsec:httpのタグ自体がauthenticationProcessingFilterに対応するものです。
これを機能拡張したい場合はauto-configをfalseに設定する必要があります。
また、関連のある以下のbean設定が必要になっています。
authenticationProcessingFilterと無関係のフィルタを作る場合には設定をする必要はありません。
auto-config ⇒属性
entry-point-ref ⇒属性
authenticationManagerAlias ⇒beanタグ
authenticationProcessingFilterEntryPoint ⇒beanタグ
注意点としては、エントリポイントも設定を別に書かなければいけないので、
sec:form-loginタグは削除します。
これ以外の通常のフィルタを作成するだけならば、
すでに説明したのフィルタの順番を指定するだけで大丈夫です!
【実行】
クラスの作成、ファイルの設定が完了したら、eclipseなどで実行してみましょう。
このとき、eclipseのコンソールウィンドウなどでみると順番が出力されますので参考までに見てみてください。
自作クラスに置き換わっているはずです。
やることはこれくらいです。
簡単ですよね。
参考:
・実際に認証と認可をWEBにつけるには? (基礎編:設定方法)
・DBのユーザ情報を使用して認証するには? (実践編:DBを使用する方法)
・ログイン後の画面にログインしたユーザを表示するには? (ログイン情報の表示方法)
・ロール(権限)によって画面のリンクの表示/非表示を制御するには?
・Anthenticationオブジェクト(SpringSecurity)とは