ApacheShiroでセッションをRedisに保存する

# 導入
こんにちは。元バックエンドエンジニアのYamaです。
以前、Springフレームワークを利用したアプリケーションのセッションをRedisで保持できるように設定したことがあるので、その内容を記事にします。
セキュリティとしてApacheShiroというライブラリを利用していたため、その時は`shiro-redis`というライブラリを利用しました。
その手順を紹介していきます。

# 手順

## 大まかな流れ
1. shiro-redis の Maven 依存関係を追加
2. Redis への接続設定
3. Shiro 設定ファイルの編集
4. ShiroConfig クラスの作成

## 詳細

### 1. shiro-redis の Maven 依存関係を追加
pom.xml に shiro-redis ライブラリを追加します。
以下の依存関係を pom.xml に追加してください。

```xml:pom.xml
<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>3.3.1</version>
</dependency>

```

### 2. Redis への接続設定
今回、記事を作成するにあたって、`AWS ElastiCache for Redis`を利用しましたが、Redisサーバーはいずれの環境のものであっても基本的に以下の設定は同様なものになります。

Redis に接続するための設定を Spring Boot のプロパティファイルに追加します。

`application.properties` または `application.yml` ファイルに以下の設定を追加します。

```properties:application.properties
spring.redis.host=<REDIS_HOST>
spring.redis.port=<REDIS_PORT>
spring.redis.password=<REDIS_PASSWORD>   # パスワードが必要ない場合は不要です
```

もしくは

```yaml:application.yml
spring:
  redis:
    host: <REDIS_HOST>
    port: <REDIS_PORT>
    password: <REDIS_PASSWORD>  # パスワードが必要ない場合は不要です
```

### 3. Shiro 設定ファイルの編集
shiro.ini や shiro-spring.xml を使用している場合、その設定を編集します。
ただし、Spring Boot では通常 Java ベースの設定クラスを使います。

### 4. ShiroConfig クラスの作成
ShiroConfig クラスを作成して、Shiro と Redis の設定を行います。

```java:ShiroConfig.java
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.ShiroFilterFactoryBean;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;

    // パスワードが設定されていない場合は不要
    @Value("${spring.redis.password:}")
    private String redisPassword;

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }

    @Bean
    public org.apache.shiro.mgt.SecurityManager securityManager(CacheManager cacheManager, SessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setCacheManager(cacheManager);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }

    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisHost + ":" + redisPort);
        // パスワードが無ければ不要
        redisManager.setPassword(redisPassword);
        return redisManager;
    }

    @Bean
    public RedisCacheManager cacheManager(RedisManager redisManager) {
        RedisCacheManager cacheManager = new RedisCacheManager();
        cacheManager.setRedisManager(redisManager);
        return cacheManager;
    }

    @Bean
    public SessionManager sessionManager(RedisSessionDAO redisSessionDAO) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO);
        return sessionManager;
    }

    @Bean
    public RedisSessionDAO redisSessionDAO(RedisManager redisManager) {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager);
        return redisSessionDAO;
    }
}

```

# 最後に
今回はApacheShiroを利用したSpringアプリケーションで、セッションをRedisに保存するための手順について紹介しました。
あまり利用する機会はないかとは思いますが、参考にしてみてください。