前提
- Angular2/4側は特に不具合がなかったので説明を割愛します。API側のみの説明になります。
- → ちなみにangular2-tokenの
.signInOAuth()
メソッドを使用して実装しました。
- → ちなみにangular2-tokenの
- 基本的に下記記事を参考にAPIを構築しております。そのため、今回遭遇した不具合に対し行った対策となる差異部分だけを記述していく形にします。
- 使用gem
gem 'rack-cors'
gem 'devise_token_auth'
gem 'omniauth'
gem 'omniauth-oauth2'
gem 'omniauth-facebook'
不具合
1. API側でFacebookのOAuth認証完了後、認証情報とユーザー情報を返す際、フロント側で認証用のポップアップウィンドウを閉じることが出来ない、かつ、送られてきた情報を取得することができない。
不具合発生の流れ
-
angular2-tokenの
.signInOAuth()
メソッドで認証用のポップアップウィンドウがhttp://localhost:3000/auth/facebook
のURLで開かれる。 - API側がFacebookに問い合わせをし、Facebookの認証画面が返却され、ポップアップウィンドウに表示される。
- 認証完了後、API側でユーザー認証をし、ユーザー情報と認証情報を返却する。
不具合の原因
不具合の流れの3で返却された情報がjson
形式のため、angular2-tokenの.signInOAuth()
メソッドではハンドリングできない。
不具合の解決方法
まず、angular2-tokenの.signInOAuth()
メソッドで返却された情報をハンドリングするためには、下記対象箇所で行っているRequest.credentials
のイベントをポップアップウィンドウ側でキャッチしなければ行けない。
対象箇所
実はgemのdevise_token_auth
で上記内容に対応するhtml
が用意されている。
そのため、レスポンスに上記html
を返すようにするだけで良い。
module Users
class OmniauthCallbacksController < DeviseTokenAuth::OmniauthCallbacksController
include Devise::Controllers::Rememberable
def omniauth_success
get_resource_from_auth_hash
create_token_info
set_token_on_resource
create_auth_params
sign_in(:user, @resource, store: false, bypass: false)
@resource.save!
# update_token_authをつけることでレスポンスヘッダーに認証情報を付与できる。
update_auth_header
yield @resource if block_given?
render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)
end
protected
def render_data(message, data)
@data = data.merge({
message: message
})
html = File.open("app/views/devise_token_auth/omniauth_external_window.html.erb").read
template = ERB.new(html).result(binding)
render html: template.html_safe
end
end
↑のomniauth_external_window.html.erb
はdevise_token_auth
のgems/devise_token_auth-0.1.42/app/views/devise_token_auth/omniauth_external_window.html.erb
をファイル指定しやすいようにapp/views/devise_token_auth
にコピーしただけのもので、内容は同じものとなります。
2. ポップアップウィンドウにFacebook認証画面が表示されている時、「後で」等で認証をキャンセルした際、エラーが発生する。
不具合発生の流れ
不具合の原因
認証をキャンセルすると本来パラメータに存在すべきキーのcode
が存在しないため、ミドルウェア段階でハンドリングされて、Devise::OmniauthCallbacksController#failure
のアクションが走る。この時、flashを使用しようする記述があるが、そもそも定義されていないのでエラーとなる。
不具合の解決方法
Devise::OmniauthCallbacksController
のfailure
をオーバーライドし、omniauth_success
のようにomniauth_external_window.html.erb
を返すようにする。
下記ファイルを作成
Rails.application.config.to_prepare do
Devise::OmniauthCallbacksController.class_eval do
def failure
@data = {
message: 'authFailure'
}
html = File.open("app/views/devise_token_auth/omniauth_external_window.html.erb").read
template = ERB.new(html).result(binding)
render html: template.html_safe
end
end
end
本来ならUsers::OmniauthCallbacksController
でomniauth_failure
をオーバーライドし、上記処理を定義したかったのですが、ミドルウェア段階でハンドリングされているらしく(詳しく処理を追えてない)暫定的な形で対応してしまいました。
もし方法がわかる方いましたらアドバイス頂けると幸いです。
その他
ここに載せていないAPIorAngular2/4側の設定だったり、記述の仕方を知りたい方は気軽にご連絡頂ければと思います。