LoginSignup
10
9

More than 5 years have passed since last update.

Rails 5.1 API mode + webpacker + react + reactstrap な ToDO アプリに Twitter OAuth 認証を追加する(Sorcery gem)

Last updated at Posted at 2018-04-12

関連記事

こちらの記事の続きです

導入手順

ドキュメントに記載されていないところで、重要なポイントは Rails API mode でプロジェクトを作成した場合には、Cookie と Session Cookie が有効になっていません (公式へのリンク)
Rails を使った方なら分かると思いますが、具体的に言えば session が使えない、ということになります

ですので、 config/application.rbActionDispatch::Session::CookieStore を有効にする必要があります。(もちろんですが、本番環境などでは MemcacheStore などを使うようにしましょう)

config/application.rb
     # Only loads a smaller set of middleware suitable for API only apps.
     # Middleware like session, flash, cookies can be added back manually.
     # Skip views, helpers and assets when generating a new resource.
     config.api_only = true

+    config.middleware.use ActionDispatch::Cookies
+    config.middleware.use ActionDispatch::Session::CookieStore

React アプリとの連携

  • 意外と悩ましいこととして、認証完了後にどのようにして React アプリ側に JWT トークンを渡すのか、という点があります
  • 大雑把に認証の流れを整理すると、以下のようになると思います
    1. OAuth 認証を行うボタンをクリック
    2. Twitter のアプリ連携確認画面に遷移
    3. アプリ連携を twitter の画面から許可
    4. Rails サーバ側にリダイレクトされる
    5. Rails サーバで認証処理を行う
    6. ...
  • 整理してみると、上記 6. のタイミングでいい感じに React アプリに JWT トークンが渡せればいい、ということになります
  • Spring Security REST の OAuth で実現している方法を パクって 参考にして、Redirect 時に JWT Token を URL パラメータとして React アプリ側に渡すようにします

サーバ側のコードに示すと以下のようになります。 def callback が twitter のアプリ連携確認画面から返ってきたときのアクションです

app/controllers/oauths_controller.rb
class OauthsController < ApplicationController
  def oauth
    login_at(params[:provider])
  end

  def callback
    provider = params[:provider]
    if @user = login_from(provider)
      # ここで JWT token 発行
      tokens = Jwt::TokenProvider.refresh_tokens @user
      # React アプリを動かしている URL にリダイレクトする
      # http://localhost:3000/#/?access_token=....&refresh_token=... という形でリダイレクトさせる
      redirect_to "#{File.join(root_url, '#', '?')}#{tokens.to_query}", notice: "Logged in from #{provider.titleize}"
    else
      begin
        @user = create_from(provider)

        reset_session
        auto_login(@user)
        # ここで JWT token 発行
        tokens = Jwt::TokenProvider.refresh_tokens @user
        # React アプリを動かしている URL にリダイレクトする
        # http://localhost:3000/#/?access_token=....&refresh_token=... という形でリダイレクトさせる
        redirect_to "#{File.join(root_url, '#', '?')}#{tokens.to_query}", :notice => "Logged in from #{provider.titleize}"
      rescue
        redirect_to root_path, :alert => "Failed to login from #{provider.titleize}"
      end
    end
  end
end

React アプリ側で params を受け取る

  • こちらは比較的簡単です
  • React Router v4 を使っている場合、 location.search で取得可能ですので、 componentDidMount のタイミングで取得するようにします
  • コードの一部を記載すると、以下のようになります
...
    let tokens = queryString.parse(get(this, "props.location.search"));
    if (!isEmpty(tokens)) {
      localStorage.setItem('access_token', tokens.access_token)
    }
...

isEmptyget はそれぞれ、lodash/isEmptylodash/get を利用しています

最後に

  • 意外と簡単に OAuth 認証を実現することができました
    • 話題が逸れますが、 「OAuth 認証」という単語は微妙らしく、 こんな記事 もあるんですね
  • URL パラメータに JWT トークンを渡すのはセキュリティ的にどうなんだろう、と疑問に思って調べてみたところ、こんな記事がありました。
10
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
10
9