2017年4月21日
はじめに ReactでSPAを作ることになって、ログイン認証にメール&パスワードの認証に加えて、 GoogleやTwitter認証も加えたくなった時、どうすればよいかわからなかった。 バックエンドはRailsだが、あくまでAPIサーバー的な立場なので メジャーなomniauth なんかは使えそうにない。。。 前回のGoogle編に続き、今回はTwitter編。 あれこれ悩みながらなんとか動くところまでたどり着いたので、やり方を公開。 React+Reduxの環境なんですが、そこまで立ち入ると話がややこしくなるので、 実装のエキス部分だけを記載してみます。 Twitter Developerにアプリ登録 Twitter Developer これについては上記のURLにアクセスしてアプリを登録してください。 アプリ名とコールバックURLを登録したら、Consumer Key (API Key)とConsumer Secret (API Secret)がもらえます。 詳しくは書きません、ググればこれはたくさん書いてあります。 動作イメージ デザインはしょぼいですが、こんな感じのログイン画面。 GoogleかTwitterで認証してログインしてね、というもの。 今回はTwitterについてのみ取り上げます。 Twitterでログインをクリックすると、Twitterが用意しているOAuth用の画面が表示されて、 Twitterのユーザー名とパスワードを入れて、最後に今回作るアプリ(SPA)へのアクセス許可画面が表示され、 許可すると、SPAアプリにログイン出来るというもの。 ステップ1(Javascript、Ajax) まずは まずはTwitterのOAuth用URLの取得のためのRails API(自作)呼び出し。 Reactの書き方なので、functionらしくないですが・・・ただのfunctionだと思ってソースを見てください。 API呼び出しの結果、OAuth用のURLが得られるので、window.openする感じです。 ポップアップというか別タブでTwitterのOAuth画面が開きます。 で、window.openしたあとは setTimeoutで1秒おきにウィンドウが閉じたかどうかをチェックします。 [bash] onLoginTwitter: (history) => { axios.get(“http://localhost:3000/get_twitter_oauth_url”, { withCredentials: true, params: {} }) .then(function (response) { windowLogin = window.open(response.data.oauth_url) setTimeout(function(){CheckLoginStatusTwitter(history)}, 1000) windowLogin.focus() }) .catch(function (response) { console.log(response); }); } [/bash] ステップ1.5(Rails) ステップ1から呼び出されるRailsのソース。 CONSUMER_IDとCONSUMER_SECRETを用いて、OAuth用のURLを取得し、JSONで結果を戻します。 [bash] require ‘oauth’ def get_twitter_oauth_url consumer = OAuth::Consumer.new( Oauth::TWITTER_CONSUMER_ID, Oauth::TWITTER_CONSUMER_SECRET, { :site => “https://api.twitter.com” } ) request_token = consumer.get_request_token( :oauth_callback => “http://localhost:3000/oauth_twitter” ) cookies[:request_token] = request_token.token cookies[:request_token_secret] = request_token.secret rtn = {} rtn[“status”] = true rtn[“oauth_url”] = request_token.authorize_url render json: rtn end [/bash] ステップ2(Javascript) ステップ1のソースのWindow呼び出しのところだけを抜粋。 RailsのAPIで戻ってきた認証用URLを引数にして window.open。 [bash] windowLogin = window.open(response.data.oauth_url) [/bash] ステップ3 ここはプログラムする必要なしです。TwitterのOAuthの画面で 純粋に認証&許可をしてもらいます。 ステップ4(Rails) Twitter側の認証と許可の処理が終わると、ステップ1.5で指定したコールバックURLに制御が戻ってきます。 テスト環境ですのでRailsのデフォルト http://localhost:3000 でサーバーが立ち上がっていて、 コールバックURLは http://localhost:3000/oauth_twitter です。 では、Railsの方の実装を見てみましょう。 最初にCONSUMER_IDとCONSUMER_SECRETを用いて、トークンを作成します。 さらに、パラメーターで渡ってきた、 oauth_tokenとoauth_verifierを使って アクセストークンを得ます。 最後に得られたアクセストークンを使ってAPIアクセスし、ユーザー情報を得ます。 で、cookiesに得られた情報をセットして、このメソッドを抜けます。 cookies[:oauth_token] = params[:oauth_token] cookies[:twitter_uid] = user_info[“id”] cookies[:screen_name] = user_info[“screen_name”] [bash] class OauthController < ApplicationController #URL /oauth_twitter への処理 def twitter consumer = OAuth::Consumer.new( Oauth::TWITTER_CONSUMER_ID, Oauth::TWITTER_CONSUMER_SECRET, { :site => “https://api.twitter.com” } ) request_token = OAuth::RequestToken.new( consumer, cookies[:request_token], cookies[:request_token_secret] ) access_token = request_token.get_access_token( {}, :oauth_token => params[:oauth_token], :oauth_verifier => params[:oauth_verifier] ) response = consumer.request( :get, ‘/1.1/account/verify_credentials.json’, access_token, { :scheme => :query_string } ) rtn = {} case response when Net::HTTPSuccess user_info = JSON.parse(response.body) if user_info[“screen_name”] cookies[:oauth_token] = params[:oauth_token] cookies[:twitter_uid] = user_info[“id”] cookies[:screen_name] = user_info[“screen_name”] else #”Authentication failed” end else #”Failed to get user info via OAuth” end end end [/bash] RailsのGemfileに以下の3つのgemを追加します。 [bash] gem ‘json’ gem ‘oauth’ gem ‘rack-cors’, :require => ‘rack/cors’ [/bash] SPAをサーブしているサーバーとAPIをサーブしているサーバーが別物になるので、 クロスドメインなAPIアクセスとなるため、API側でそれを許可する必要があります。 gem rack-cors でそれに対応できます。で、対応するためにapplication.rbを 以下のように書き換えます。 本番ではoriginsは「*」ではなく、ちゃんと特定のドメイン名を入れるべし。 config/application.rb [bash] class Application < Rails::Application config.middleware.insert_before ActionDispatch::Static, Rack::Cors do allow do origins '*' resource '*', :headers => :any, :methods => [:get, :post, :delete] end end end [/bash] ステップ5(RailsのJavascript) OauthControllerのtwitterメソッドで処理をしたので、普通に処理が終われば、ポップアップ画面には そのメソッドに対応するビューが表示されます。 なので、対応するビューは作るのですが、あくまでダミーで結構です。 そもそも、ポップアップ(別タブ)でTwitter認証が開いていて、認証が終わればポップアップは閉じてほしい はずですので・・・ で、assets/javascripts 配下に以下のようなJavaScript(CoffeeScriptではない)を作ります。 ファイル名はなんでもいい。 で、ここでする処理は、ダミーのビューが表示された時にそのhrefをチェックして、 認証終了のダミービューだと判定できたら、window.closeしてやるというものです。 [bash] $(function(){ if (window.location.href.indexOf(“oauth_twitter”) >0){ window.close(); }…
Leave a comment