SpringSecurityで認証を設定する
SpringSecurityを使うと、Webアプリケーションの認証機構をSpringSecirityに一任できます。例えばログインやログアウトのURLや、CSRF(クロスサイト・リクエスト・フォージャリ)を回避するトークンの発行も簡単に設定可能です。
SpringSecurityの設定例
今回は以下を想定した設定にします。
- FORM認証を使う
- CSRFの回避を自動で行う
- Spring4シリーズで統一する
applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns:sec="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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<sec:http auto-config='true'>
<!-- CSRF回避チェックを有効 -->
<sec:csrf/>
<!-- アクセス制御をしないURLを定義 -->
<sec:intercept-url pattern="/login*" access="permitAll"/>
<sec:intercept-url pattern="/css/**" access="permitAll" />
<sec:intercept-url pattern="/fonts/**" access="permitAll"/>
<sec:intercept-url pattern="/images/**" access="permitAll"/>
<sec:intercept-url pattern="/js/**" access="permitAll"/>
<sec:intercept-url pattern="/templates/**" access="permitAll"/>
<!-- ロールに ROLE_ADMIN を持つユーザID(USERNAME)のみアクセス許可 -->
<sec:intercept-url pattern="/*" access="hasRole('ROLE_ADMIN')" />
<!-- FORM認証の振る舞い -->
<sec:form-login
login-page="/login.action"
login-processing-url="/j_spring_security_check"
username-parameter="j_username"
password-parameter="j_password"
authentication-failure-url="/loginFailure.action" />
<!-- ログアウト時の振る舞い -->
<sec:logout
logout-url="/logout"
logout-success-url="/logout.action"
invalidate-session="true" />
</sec:http>
<!-- データベースを使った認証管理 -->
<sec:authentication-manager alias="authManager">
<sec:authentication-provider>
<sec:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT
USERNAME
, PASSWORD
, ENABLED
FROM
USERTABLE
WHERE
USERNAME = ?"
authorities-by-username-query="
SELECT
USERNAME
, AUTHORITY
FROM
ROLETABLE
WHERE
USERNAME = ?"
/>
</sec:authentication-provider>
</sec:authentication-manager>
<beans:bean
id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
</beans:beans>
SpringSecurity4ではSpringELを使った設定になります。3.xまでの記述では動作しません。
ログアウトのURLを選択しても、実はセッションが残っている場合がある
さて、先ほどのxmlにてログアウト時のURLは、/logout と定義しました。
この設定そのものは間違いないのですが、CSRF回避チェックを有効にしている場合は、アンカータグやリダイレクトで /logout を指定すると、確かにログアウトページを表示しますが、なんとセッションが破棄されません。
この理由は CSRFチェックが有効だから です。
個人的にはややもんにょりしますが (´・ω・`)
このため、ログアウトを行う際には必ず次のルールを守ります。
- <form>を使う
- HTTP-METHODはPOST必須
- CSRFチェックの送信パラメータを設定する
実装例は以下のようになります。
送信ボタンなどはつけずに、JavaScriptから送信する例です。
header.jsp(+JSTL)
<c:url var="logoutUrl" value="/logout"/>
<form id="logoutForm" action="${logoutUrl}" method="POST">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
</form>
header.html(thymeleaf-2.1)
<form id="logoutForm" th:action="@{/logout}" method="POST">
<input type="hidden"
th:name="${_csrf.parameterName}"
th:value="${_csrf.token}"/>
</form>