認証機能をSpringSecurityに任せる
Struts2は特に認証用の機能はありません。
サーブレット標準の認証(JAAS)を使いログイン/ログアウトを構築できますが、それよりも高度な機構を備えるSpringSecurityを組み合わせることで、認証ならびにアクセス制御をSpringSecurityに任せ、ログイン後やログアウト後の追加処理をStruts2で実装することも可能です。
必要なjarファイルたち(mavenで設定)
以下の設定はSpringSecurity-4.0.0.CI版のものですが、正式リリース後はCIをRELEASEに置き換えるだけです。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>archetype.group.id</groupId>
<artifactId>artifactId</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.7</java.version>
<spring-security.version>4.0.0.CI-SNAPSHOT</spring-security.version>
<struts2.version>2.3.20</struts2.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>${struts2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>${struts2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<name>appname</name>
<url>http://your.domain/appname</url>
<description>descriptions....</description>
</project>
設定ファイルの修正・追加
SpringSecurityのサーブレットフィルタを有効にします。以下のxmlファイルを編集します。
- web.xml
- applicationContext-security.xml(ファイル名はweb.xmlに記載したもの)
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="app_id" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>appname</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml,classpath:spring/applicationContext-*.xml</param-value>
</context-param>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
</web-app>
applicationContext-security.xml
この例では別途 Springの定義で、JDBCのデータソースを dataSourceの名前で定義が必要です。web.xmlにて、配置名をclasspath:spring/applicationContext.xml,classpath:spring/applicationContext-*.xml と宣言しています。配置場所はお好みでどうぞ。
私の場合はspringディレクトリを作成し、その中に 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>
認証するための情報を取得する先は、<sec:authentication-manager alias="authManager">\で定義します。この例ではSQLを発行してデータベースに問い合わせます。データベース接続はSpring管理下にある dataSource の名前で管理されたSpring-beanです。
dataSourceの設定例をおまけで次に紹介します。
applicationContext-dataSource.xml
Spring管理下でdataSourceを作ります。
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-autowire="byName"
>
<!-- Springトランザクション管理クラス -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<!-- トランザクション定義でSpringアノテーション利用を宣言する。 -->
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
<!-- JNDIルックアップ -->
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/dbcon"></jee:jndi-lookup>
</beans>
この例では、データベース接続のソースをTomcatなどのコンテナから拝借します。その際、JNDIで定義した命名で指定します。
データソースを使う場合には、pom.xmlにて必要なSpring frameworkを追加します。
以下は追加例です。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>artifactId</artifactId>
<name>appname</name>
<properties>
<!-- ここから追加 -->
<spring.version>4.1.3.RELEASE</spring.version>
<!-- ここまで -->
</properties>
<dependencies>
<!-- ここから追加 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- ここまで -->
</dependencies>
</project>