はじめに
今回は、Spring BootアプリケーションのセッションをDBで管理する方法を調べたので備忘録として書いていきます。
書いてある内容は手を動かして確認したものですが、正しい情報は公式ドキュメント(以下は2.4.3のもの)の内容を見てください。 Spring Session - Spring Boot
環境
- Spring Boot 2.4.5
- Maven 3.6.3
- Kotlin 1.3.72-release-468
- Docker version 20.10.8, build 3967b7d
- MySQL 5.7
spring-session-jdbcの依存を追加
Spring Session JDBC を利用するため、pom.xmlにspring-session-jdbcを追加します。 Spring Session JDBCは、RDBを使ったSessionRepositoryの実装クラスと、関連する設定を提供するライブラリです。
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-jdbc</artifactId> </dependency>
セッション関連の設定を追加
application.properties(application.yml)にセッションに関連する設定を追加していきます。
spring.session.store-type=jdbc spring.session.jdbc.initialize-schema=embedded spring.session.jdbc.table-name=SPRING_SESSION server.servlet.session.timeout=30m
spring.session.jdbc.initialize-schemaは、スキーマの初期化をどういう条件で実行するのかを設定するプロパティです。ALWAYSであれば常にDBの初期化が行われ、EMBEDDEDであればembedded databaseに対してのみ初期化が行われ、NEVERであればデータベースの初期化を行わない、という挙動になります。 spring.session.jdbc.table-nameはセッションを格納するテーブル名を設定するプロパティです。ここで設定されたテーブルにセッションを格納します。
データベースの接続情報の設定を追加
application.properties(application.yml)にデータベースの接続情報の設定を追加していきます。
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sample spring.datasource.username=user spring.datasource.password=password
セッションを格納するテーブルを作成する
デフォルトでは、SPRING_SESSION, SPRING_SESSION_ATTRIBUTESテーブルにセッションを格納するため、 以下のリポジトリで管理されているスキーマごとのSQLを実行してテーブルをデータベースに作成します。 https://github.com/spring-projects/spring-session/tree/main/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc
今回は、SpringBootアプリケーションコンテナとは別に、DockerでMySQLコンテナを立ち上げるので、その初期化SQLに↑で管理されているMySQL用のスキーマを記述します。
DROP TABLE IF EXISTS SPRING_SESSION; CREATE TABLE SPRING_SESSION ( PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, EXPIRY_TIME BIGINT NOT NULL, PRINCIPAL_NAME VARCHAR(100), CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ) ENGINE = InnoDB ROW_FORMAT = DYNAMIC; CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME); DROP TABLE IF EXISTS SPRING_SESSION_ATTRIBUTES; CREATE TABLE SPRING_SESSION_ATTRIBUTES ( SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION (PRIMARY_ID) ON DELETE CASCADE ) ENGINE = InnoDB ROW_FORMAT = DYNAMIC;
セッションとして格納するクラスをSerializableにする
今回はSpring Securityで提供されているログイン機能を使うため、UserDetailsクラスを実装したクラスをセッション情報として格納します。 セッション情報として格納するクラスはSerializableなクラスとして実装する必要があるため、Serializableインターフェースを実装するよう変更します。
data class TodoUser( val userId: String, val userName: String, val password: String ) : Serializable
動作確認
実際にサンプルアプリケーションを立ち上げてログインしてみると、SPRING_SESSION, SPRING_SESSION_ATTRIBUTESテーブルにレコードが作成されていることが確認できます。
参考資料
https://docs.spring.io/spring-session/docs/2.4.3/reference/html5/guides/boot-jdbc.html