Railsのセッション保存場所をCookieからRedisに変更する方法

Ruby

Railsのセッション情報はデフォルトでCookieに保存されます。
Railsのセッション管理方法は変更が可能で、Cookieの代わりにインメモリDBを採用するケースがよくあります。

今回はセッションの管理方法をCookieからインメモリDBであるRedisに変更する方法について紹介します。

セッション管理をCookieからRedis(インメモリDB)に変えるメリット・デメリット

メリット
  • Cookieで管理するデータ量が減る
  • CookieではセッションIDのみを管理すればよくなるため、情報漏洩のリスクが減る
  • インメモリDBなので高速な処理が可能
デメリット
  • インメモリDBは高速だがCookieに比べると処理が遅い
  • Redisを導入するコストがかかる
  • Redisに障害が発生すると、セッション機能が使えなくなる

Redisのインストール

RailsアプリケーションでRedisを利用する前に、まずはRedis本体をインストールします。

ローカル環境の場合

### redisのインストール
$ brew install redis

### redisサーバの起動
$ redis-server

Docker環境の場合

Redis用のコンテナをdocker-compose.ymlに追加すればOKです。

docker-compose.yml

version: '3'
services:
  app: # アプリケーションコンテナ
    ...
    ...
  (略)
    depends_on:
      - redis # redisコンテナを依存関係に追加
  redis: # Redisコンテナ
    image: redis:latest
    volumes:
      - redis-data:/data # Redisデータの永続化
volumes:
  redis-data:

RailsアプリケーションにRedisを組み込む

RailsアプリケーションでRedisを利用する手順について紹介します。

gemのインストール

Redisを導入する際に利用するgemはredis-railsが有名です。
redis-railsはRailsアプリケーションのストア機能(キャッシュ、セッション、HTTPキャッシュ)をセットで提供するgemです。

しかしredis-railsのREADMEにも書いてあるように、セッション管理でRedisを使う場合はredis-actionpackの利用が推奨されているので、今回はredis-actionpackを利用します。

Gemfile

gem 'redis-actionpack'
$ bundle install

セッション管理の設定を作成

redis-actionpackのREADMEを参考に、設定を記載します。

セッション管理の設定はconfig.session_storeで行います。
config.session_store:redis_storeにすることでRedisがセッション管理で利用されます。

:redis_storeで設定できるオプションと意味は以下の通りです。1

オプション 意味
servers Redisへの接続情報
expire_after セッションキーのデフォルトのTTL(Time to live)
key セッションIDを保存するCookieの名前
threadsafe スレッドセーフに関するフラグ。デフォルトはtrue
secure サーバからクライアントへのCookie転送でHTTPS通信を利用するかのフラグ
signed 署名/暗号化されたCookieの利用に関するフラグ
httponly HttpOnlyに関するフラグ

なお、serversredis://<ホスト名>:<ポート番号>/<db番号>/<ネームスペース>という命名規則です。SSL通信でRedisに接続する場合はredisの部分をredissにします。

たとえば以下のようになります。

config/initializers/session_store.rb

Rails.application.config.session_store :redis_store,
  servers: %w(redis://localhost:6379/0/session),
  # ホスト: localhost(docker環境の場合はredisコンテナ名)
  # ポート: 6379
  # DB: 0番
  # ネームスペース: session
  expire_after: 90.minutes, # 有効期限90分
  key: "_#{Rails.application.class.parent_name.downcase}_session" # キー名

環境ごとに設定を変えたい場合はconfig/environments/配下の環境ファイルに設定を記述します。

config/environments/development.rb

Rails.application.configure do
  (略)
  config.session_store :redis_store,
    servers: %w(redis://redis:6379/0/session),
    ...
    ...
end

Cookie方式とRedis方式のセッション情報管理の違いを確認する

Railsアプリケーションを起動し、Cookie方式とRedis方式の違いについて確認します。

Cookie方式の場合

Cookieにセッション情報がすべて保存されています。

Redis方式の場合

Cookie方式に比べ、Cookieに保存されている情報が少ないことがわかります。Redis方式の場合、Redisで管理されたセッション情報を取り出すためのIDだけがCookieに保存されます。

この時、Rails側でセッションに保存されているセッションIDを取得するとCookieに保存されている値と同じであることが確認できます。
RailsにおけるセッションとCookieの操作方法の詳細解説はRailsでセッションとCookieを操作する方法で紹介しています。

    2: def index
 => 3:   binding.pry
    4: end

### Railsアプリケーションのセッションの保存先のCookie
> cookies[:_simpledevise_session]
=> "050c90ea9d875a5d11e04fe1274fc76f"

### セッションのキー一覧
> session.keys
=> ["_csrf_token"]

### セッションの値
> session[:_csrf_token]
=> "JqT7GxIDePWWOTihYTDee2NVUFCTma+9Cg9vSIlhOH4="

### セッションID
# Cookieの値と同じ、つまりCookieにはセッションIDが保存されている
session[:session_id]
=> "050c90ea9d875a5d11e04fe1274fc76f"

セッション情報はredis-cliで確認できます。
アプリケーションにアクセスした後、redis-cliでRedisの中身を確認すると、セッション情報の保存されたレコードが確認できます。

### redis-cliで接続
$ redis-cli -h localhost -p 6379 -n 0 --raw
# -h: ホスト指定
# -p: ポート指定
# -n: データベース選択
# --raw: マルチバイト文字の文字化けを防ぐ

### DBの選択(0~15まで選択)
> select 0

### 保存されているキーの数
> dbsize
1

### キーの一覧
> keys *
session:2::75605b9406802923576fc9d1d07df5d211cad8f380ff3a8dcb30a53612d02de1
# 接頭辞の『session:』部分がネームスペースに該当する
# ネームスペースを指定しない場合は『2::xxxxx』のようになる

### valueの種類の確認
> type session:2::75605b9406802923576fc9d1d07df5d211cad8f380ff3a8dcb30a53612d02de1
string

### valueの確認(stringのvalueはgetで取得する)
# session[:_csrf_token]の参照元
> get session:2::75605b9406802923576fc9d1d07df5d211cad8f380ff3a8dcb30a53612d02de1

{I"_csrf_token:EFI"1JqT7GxIDePWWOTihYTDee2NVUFCTma+9Cg9vSIlhOH4=;F

### 終了
> exit

なお、redis-cliではflushdbでデータベースの全てのレコードが、del keyで対応するkeyのレコードが削除できます。

まとめ

今回のまとめ
  • Redisをセッション管理に利用すると、Cookieで不要なデータを持たなくて済む
  • RedisはインメモリDBなので高速な処理が可能
  • Redisサーバを用意し、設定とgemを追加することでRailsとRedisの連携が可能

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

Rubyのオススメ参考書