28
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ActionCable内でRedisに保存したセッションからログインユーザーデータを取得する

Last updated at Posted at 2016-11-17

#まえがき
リアルタイムWebアプリケーションを開発していると、channel内でログイン情報を扱いたくなる時がよくあると思います。

ActionCable内でセッションストアをCookieStoreにした場合の
ログイン情報の取得例はいくつかサンプルがありましたが、
セッションストアにRedisを利用している場合のサンプルがなかったのでまとめておきます。

#環境
Ruby: 2.3.1
Rails: 5.0.0.1

で試しています。

RailsのセッションストアをRedisにする

まずはセッションストアをredisにする為に以下のGemをインストールします。
また、Redisを扱いやすくするためにredis-namespaceも利用しています。

gem 'redis'
gem 'redis-rails'
gem 'redis-namespace'

続いて以下のファイルを設定します。

config/initializers/session_store.rb

Rails.application.config.session_store :redis_store, {
  servers: {
    host: 'localhost',
    post: 6379,
    db: 0,
    namespace: 'sessions'
  },
  key: 'sessions',
  expire_after: 1.day
}

ユーザーデータをcookieに書き込む

ログイン認証部分でsessionにデータをセットしたあとにCookieにuser_idをいれておきます。

	def login
	  # ユーザーデータをセット
	   session[:user_id] = 1
	   session[:nickname] = "test"
	   
      # signed cookieにuser_idを持っておく
      cookies.signed[:user_id]  = user["user_id"]
    end
      

redis側の設定

config/redis.yml

development:
  hosts:
  - localhost
  db:
    session: 0
test:
  hosts:
  - localhost
  db:
    session: 0
production:
  hosts:
  - <%= ENV['REDIS_HOST'] %>
  db:
    session: 0

ActionCable内でユーザーログイン状態を取得する

ActionCable内では通常のsessionは利用できません。
そのため、WebSocket経由で送られてくるCookieからuser_idを特定し、session_dataを取得する必要があります。
ApplicationCable内ではidentified_byで指定した値でユーザーを識別することができます。

app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      val = session_from_redis
      if val
        self.current_user = {
          user_id:  val["user_id"],
          nickname: val["nickname"]
        }
      end
    end

    def session_from_redis
      # redisのsessionのnamespaceを取得
      redis_namespace = Rails.application.config.session_options[:servers][:namespace]

      # session cookieの名前を取得
      cookie_key = cookies[Rails.application.config.session_options[:key]]

      # redis内にあるsession_keyを組み立てる
      session_key = "#{redis_namespace}:#{cookie_key}"

      # redisからsessionを取得
      redis = CustomRedis.new({'db' => 'session'})
      val = redis.get(session_key)

      # Marshalされているのでdecode
      val ? Marshal.load(val) : nil
    end
  end
end

ユーザーデータの参照

channel内でもcurrent_userからユーザーデータを取得することが可能です

app/channels/room_channel.rb
class RoomChannel < ApplicationCable::Channel
  def subscribed
    stream_from "room_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def speak(data)
    ai = AI::Engine.new(user_id: current_user[:user_id], nickname: current_user[:nickname])
    ai.trigger(data['message'])
  end
end

#まとめ

実際に運用する場合は細かいエラー処理やセキュリティ対策などが必要ですが、簡易的に保存&取得したい場合はこのような手法でログイン情報をやり取りすることができます。

28
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?