Spring Session および Spring Security と Hazelcast
このガイドでは、Hazelcast をデータストアとして使用するときに Spring Session を Spring Security と一緒に使用する方法について説明します。Spring Security がすでにアプリケーションに適用されていることを前提としています。
完成したガイドは Hazelcast Spring Security サンプルアプリケーションにあります。 |
依存関係の更新
Spring Session を使用する前に、依存関係を更新する必要があります。Maven を使用する場合は、次の依存関係を追加する必要があります。
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>6.2.3</version>
</dependency>
</dependencies>
Spring の設定
必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession
実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。これを行うには、次の Spring 構成を追加します。
@EnableHazelcastHttpSession (1)
@Configuration
public class HazelcastHttpSessionConfig {
@Bean
public HazelcastInstance hazelcastInstance() {
Config config = new Config();
AttributeConfig attributeConfig = new AttributeConfig()
.setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
.setExtractorClassName(PrincipalNameExtractor.class.getName());
config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) (2)
.addAttributeConfig(attributeConfig)
.addIndexConfig(
new IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
SerializerConfig serializerConfig = new SerializerConfig();
serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class);
config.getSerializationConfig().addSerializerConfig(serializerConfig); (3)
return Hazelcast.newHazelcastInstance(config); (4)
}
}
1 | @EnableHazelcastHttpSession アノテーションは、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成します。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この場合、Spring Session は Hazelcast によってサポートされています。 |
2 | プリンシパル名インデックスによるセッションの取得をサポートするには、適切な ValueExtractor を登録する必要があります。Spring Session は、この目的のために PrincipalNameExtractor を提供します。 |
3 | MapSession オブジェクトを効率的に直列化するには、HazelcastSessionSerializer を登録する必要があります。これが設定されていない場合、Hazelcast はネイティブ Java 直列化を使用してセッションを直列化します。 |
4 | Spring Session を Hazelcast に接続する HazelcastInstance を作成します。デフォルトでは、アプリケーションが起動し、Hazelcast の組み込みインスタンスに接続します。Hazelcast の構成の詳細については、リファレンスドキュメント (英語) を参照してください (英語) 。 |
HazelcastSessionSerializer が優先される場合は、開始する前に、すべての Hazelcast クラスターメンバーに対して構成する必要があります。Hazelcast クラスターでは、すべてのメンバーがセッションに同じ直列化方法を使用する必要があります。また、Hazelcast クライアント / サーバートポロジを使用する場合は、メンバーとクライアントの両方で同じ直列化方法を使用する必要があります。シリアライザーは、同じ SerializerConfiguration のメンバーに ClientConfig を介して登録できます。 |
サーブレットコンテナーの初期化
Spring の設定は、Filter
を実装する springSessionRepositoryFilter
という名前の Spring Bean を作成しました。springSessionRepositoryFilter
Bean は、HttpSession
を Spring Session によるカスタム実装に置き換えるロールを果たします。
Filter
がその魔法を実行するために、Spring は SessionConfig
クラスをロードする必要があります。このアプリケーションは、SecurityInitializer
クラスを使用して Spring 構成をすでにロードしているため、SessionConfig
クラスをアプリケーションに追加できます。次のリストは、その方法を示しています。
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(SecurityConfig.class, SessionConfig.class);
}
}
最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter
を使用するようにする必要があります。Spring Session の springSessionRepositoryFilter
は、Spring Security の springSecurityFilterChain
の前に呼び出されることが非常に重要です。そうすることで、Spring Security が使用する HttpSession
が Spring Session によって確実にサポートされます。幸い、Spring Session には、これを簡単に実行できる AbstractHttpSessionApplicationInitializer
という名前のユーティリティクラスが用意されています。次の例は、その方法を示しています。
public class Initializer extends AbstractHttpSessionApplicationInitializer {
}
クラスの名前(Initializer )は関係ありません。重要なのは、AbstractHttpSessionApplicationInitializer を継承することです。 |
AbstractHttpSessionApplicationInitializer
を継承することにより、springSessionRepositoryFilter
という名前の Spring Bean が、Spring Security の springSecurityFilterChain
の前のすべてのリクエストに対してサーブレットコンテナーに登録されるようにします。
Hazelcast Spring Security サンプルアプリケーション
このセクションでは、Hazelcast Spring Security サンプルアプリケーションの操作方法について説明します。
サンプルアプリケーションの実行
サンプルを実行するには、ソースコードを取得し、次のコマンドを呼び出します。
$ ./gradlew :spring-session-sample-javaconfig-hazelcast:tomcatRun
デフォルトでは、Hazelcast はアプリケーションで組み込みモードで実行されます。ただし、代わりにスタンドアロンインスタンスに接続する場合は、リファレンスドキュメント (英語) の手順に従って構成できます。 |
これで、localhost:8080/ でアプリケーションにアクセスできるようになります。
セキュリティサンプルアプリケーションの調査
これで、アプリケーションを使用してみることができます。これを行うには、以下を入力してログインします。
ユーザー名 user
パスワード password
次に、ログインボタンをクリックします。以前に入力したユーザーでログインしていることを示すメッセージが表示されます。ユーザーの情報は、Tomcat の HttpSession
実装ではなく Hazelcast に保存されます。
それはどのように機能しますか?
Tomcat の HttpSession
を使用する代わりに、Hazelcast で値を保持します。Spring Session は、HttpSession
を、Hazelcast の Map
による実装に置き換えます。Spring Security の SecurityContextPersistenceFilter
が SecurityContext
を HttpSession
に保存すると、Hazelcast に永続化されます。
新しい HttpSession
が作成されると、Spring Session はブラウザーに SESSION
という名前の Cookie を作成します。その Cookie には、セッションの ID が含まれています。Cookie を表示できます(Chrome (英語) または Firefox [Mozilla] (英語) を使用)。
データストアとのやり取り
Java クライアント (英語) 、他のクライアントの 1 つ (英語) 、または管理センター (英語) を使用して、セッションを削除できます。
コンソールの使用
例: Hazelcast ノードに接続した後に管理センターコンソールを使用してセッションを削除するには、次のコマンドを実行します。
default> ns spring:session:sessions spring:session:sessions> m.clear
Hazelcast のドキュメントには、コンソール (英語) の説明があります。 |
または、明示的なキーを削除することもできます。コンソールに次のように入力します。必ず 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
を SESSION
Cookie の値に置き換えてください。
spring:session:sessions> m.remove 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
次に、localhost:8080/ のアプリケーションにアクセスして、認証されなくなったことを確認します。
REST API の使用
他のクライアントをカバーするドキュメントのセクションに従って、Hazelcast ノードによって提供される REST API (英語) があります。
例: 次のように個々のキーを削除できます(7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
を必ず SESSION Cookie の値に置き換えてください)。
$ curl -v -X DELETE http://localhost:xxxxx/hazelcast/rest/maps/spring:session:sessions/7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Hazelcast ノードのポート番号は、起動時にコンソールに出力されます。xxxxx をポート番号に置き換えます。 |
これで、このセッションで認証されなくなったことがわかります。