はじめに
mkcertとSorceryの拡張機能を用いて、ローカル環境でfacebook認証機能を追加しました。
Sorceryのwikiが少し古かったり、facebook for developersとの連携に苦戦したので、備忘録がてら書いておこうと思います。
また、設定に不備があった場合のエラーについてはこちら で書いています。
動作環境
ruby 2.6.5
Rails 5.2.3
sorcery 0.14.0
mkcert 1.4.1
前提
sorceryによるログイン機能
mkcertでのHTTPS通信を許可
facebook for developersで「facebookログイン」の作成
は済ませていることとします。
簡単な流れ
Sorceryのwiki にチュートリアルがあるので、基本的にはそれに従っていきます。
authenticationsテーブルを作成
1
2
3
4
$ rails g sorcery:install external --only-submodules
gsub config/initializers/sorcery.rb
insert app/models/user.rb
create db/migrate/20200203110653_sorcery_external.rb
コマンドを打つと、外部認証に必要なauthenticationsテーブルを作成するためのマイグレーションファイルが作られます。
1
2
3
4
5
6
7
8
9
10
11
12
13
class SorceryExternal < ActiveRecord :: Migration
def change
create_table :authentications do | t |
t . integer :user_id , :null => false
t . string :provider , :uid , :null => false
t . timestamps
end
add_index :authentications , [ :provider , :uid ]
add_index :authentications , :user_id # user_idにindexを貼る場合は追加
end
end
$ bundle exec rails db:migrate
Authenticationモデルの設定
$ rails g model Authentication –migration=false
先ほど既にマイグレーションファイルは作成しているので、--migration=false
オプションを付けています。
1
2
3
class Authentication < ActiveRecord :: Base
belongs_to :user
end
1
2
3
4
5
class User < ApplicationRecord
authenticates_with_sorcery!
has_many :authentications , dependent : :destroy
accepts_nested_attributes_for :authentications # has_many :authenticationsより下に書く
end
ここまではfacebook認証に限らず、外部認証共通の処理となります。
sorcery.rbの設定
sorcery.rbの以下の部分のコメントアウトを外します。
blabla
って何のことだ?って思ったんですが、英語で「などなど」って意味なんですね。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Rails . application . config . sorcery . submodules = [ :external , blabla , blablu , ...] # コマンドを打つと自動的に追加される
Rails . application . config . sorcery . configure do | config |
...
config . external_providers = [ :facebook , blabla , ...] # 外部認証に使用するもののみ追加
# 例 [:twitter, :facebook, :github, :linkedin, :xing, :google, :liveid, :salesforce, :slack, :line]
...
config . facebook . key = Rails . application . credentials . dig ( :sorcery , :facebook , :key ) # 1.で解説
config . facebook . secret = Rails . application . credentials . dig ( :sorcery , :facebook , :secret ) # 1.で解説
config . facebook . callback_url = 'https://localhost:3000/oauth/callback?provider=facebook' # 2.で解説
config . facebook . user_info_path = 'me?fields=email' # 3.で解説
config . facebook . user_info_mapping = { email : 'email' } # 3.で解説
config . facebook . access_permissions = %w[email] # 3.で解説
config . facebook . display = 'page'
config . facebook . api_version = 'v6.0' # 4.で解説
config . facebook . parse = :json
...
# --- user config ---
config . user_config do | user |
...
# -- external --
user . authentications_class = Authentication # 認証用のモデルがAuthenticationではない場合は変更する
...
end
...
end
config.facebook
に関する最初の3行は、環境によって値を変更することになると思いますが、ここでは省略します。Config などを使ってください。
1. facebook keyとsecret
facebook keyとsecretは外部には漏らしたくないため、credentials で管理します。
参考:Rails5.2から追加されたcredentials.yml.encのキホン
$ rails credentials:edit
1
2
3
4
5
# ここの構成は自由ですが、Rails.application.credentials.dig(:sorcery, :facebook, :key)のように対応するようにしてください。
sorcery :
facebook :
key : 'アプリIDの値'
secret : 'app secretの値'
facebook for developers からマイアプリにアクセスし、「ダッシュボード」下の「設定」→「ベーシック」の画面から「アプリID」と「app secret」を確認し、記述してください。
IDは15桁の数字、secretは英数字のハッシュとなっています。
2. callback_url
HTTPS化をしているため、デフォルトの"http://0.0.0.0:3000/oauth/callback?provider=facebook"
ではエラーが出ます。
SSL証明書の発行されているhttps://localhost:3000/oauth/callback?provider=facebook
をここに記述します。
そして、「Facebookログイン」「設定」の「有効なOAuthリダイレクトURI」にも同じものを登録します。
3. facefookから取得するデータ
デフォルトでfacebookから取得できるデータは以下の通りです。
id
first_name(名)
last_name(姓)
middle_name(ミドルネーム)
name(フルネーム)
name_format(デフォルトは{last}{first}
)
picture(プロフィール画像)
short_name(設定されていない場合はフルネーム)
アクセス許可のリファレンス
それ以外のデータを取得したい場合は、config.facebook.access_permissions
に記述します。
emailを取得するためにはfacebook側の手続きは要りませんが、それ以外にはアプリレビューが必要です。
Email、姓名、プロフィール画像を取得してUserに入れる場合はこのようになります。
1
2
3
4
5
6
config . facebook . user_info_path = 'me?fields=email,first_name,last_name,picture.type(large)'
# facebookから取得するデータの受け取り方
config . facebook . user_info_mapping = { email : 'email' , first_name : 'first_name' , last_name : 'last_name' , remote_avatar_url : 'picture/data/url' }
# facebook側の属性名とUserモデルの属性を対応させる
config . facebook . access_permissions = %w[email]
# デフォルト以外のデータを取得する場合はここに書く
プロフィール画像の取得方法は他と少し違うので注意が必要です。
参考:Sorcery + CarrierWaveでFacebook認証時に大きめのアイコン画像を保存する
4. APIのバージョン
facebook APIのバージョン は「Facebookログイン」の「クイックスタート」から「ウェブ」「2. JavaScript用Facebook SDKを設定する」で確認できます。
参考:自分が管理するFacebookアプリのAPIバージョン確認方法
少しレイアウトが変わっていますが、こちらの方法でも確認できます。
Oauth処理を行うコントローラを作成
$ rails g controller Oauths oauth callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class OauthsController < ApplicationController
skip_before_action :require_login # applications_controllerでbefore_action :require_loginを設定している場合
def oauth
login_at ( auth_params [ :provider ] )
end
def callback
provider = auth_params [ :provider ]
if ( @user = login_from ( provider ))
redirect_to root_path , notice : " #{ provider . titleize } でログインしました"
else
begin
@user = create_from ( provider )
reset_session
auto_login ( @user )
redirect_to root_path , notice : " #{ provider . titleize } でログインしました"
rescue StandardError
redirect_to root_path , alert : " #{ provider . titleize } でのログインに失敗しました"
end
end
end
private
def auth_params
params . permit ( :code , :provider )
end
end
基本的にはチュートリアルの通りです。多少、Rails5の書き方に直します。
ログインボタンを追加
1
<%= link_to 'Login with Facebook' , auth_at_provider_path ( provider : :facebook ) %>
ルーティングの追加
1
2
3
post "oauth/callback" , to : "oauths#callback"
get "oauth/callback" , to : "oauths#callback"
get "oauth/:provider" , to : "oauths#oauth" , as : :auth_at_provider
oauth_callback POST /oauth/callback(.:format) oauths#callback
GET /oauth/callback(.:format) oauths#callback
auth_at_provider GET /oauth/:provider(.:format) oauths#oauth