Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 5 years have passed since last update.
DeviseとOmniauthでtwitter,facebook ログイン機能
はじめに
自分が実装しているときに割とハマったので書きました。
deviseでuserモデルを作成するとこから始めます。
公式ドキュメント
github-devise-wiki OmniAuth: Overview
参考資料
Devise+OmniAuthでQiita風の複数プロバイダ認証-Qiita
Rails5.2から追加された credentials.yml.enc のキホン-Qiita
[Rails]gem "OmniAuth" の脆弱性対策-Qiita
secrets.ymlや環境変数をRails 5.2のEncrypted Credentialsに移行する
gem
以下のgemを追加して bundle install します。
gem"devise"gem'omniauth'gem'omniauth-facebook'gem'omniauth-twitter'deviseのインストール
$ rails g devise:install create config/initializers/devise.rb create config/locales/devise.en.yml===============================================================================Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p><%= notice %></p> <p><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views上の4つを行ってください。
userモデルの設定
userモデルを作成
$ rails g devise User:models/user.rbclassUser<ApplicationRecord# Include default devise modules. Others available are:# :confirmable, :lockable, :timeoutable, :trackable and :omniauthabledevise:database_authenticatable,:registerable,:recoverable,:rememberable,:validatable,:omniauthable# :omniauthableを追加してください。endでbundle install します。
omniauth用のカラムをuserモデルに追加して行きます。↓
oauth認証時にproviderの名前(facebook,twitter)、uid(providerのユーザーID)がいるみたいなので追加します。
また、image,nameも取得したいので追加します。
$ rails g migration add_columns_to_users provider uid name image$ rake db:migrateTwitter DeveloperとFacebook Developerのアカウント作成
すいませんが以下のサイトを見てください。詳しく書いてあります。
Twitter Developer
Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ ※2018年9月時点の情報-Qiita
Facebook Developer
【2019年】これで完璧!Facebook Developerに登録する方法を図解つきで説明
Developerでアプリを作成
アカウントを作成したら、Developerでアプリを作成してください。
Twitter Developer
Twitter Developerでは Callback URLにhttps://127.0.0.1:3000/users/auth/twitter/callback(127.0.0.1:3000にはprodction用のurl)http://localhost:3000/users/auth/twitter/callback
この2つを記入してください。
Facebook Developer
またこのサイトを見てもらって、
【2019年】これで完璧!Facebook Developerに登録する方法を図解つきで説明
ダッシュボード下の設定→ベーシック→ウェブサイトのサイトurlに
ローカルだけで試すのであればhttp://localhost:3000
ローカルと本番環境(heroku)
自分のサイトのurl
を記入してください。
本番環境では有効なOAuthリダイレクトURIの設定が必要
facebookログイン下の設定→有効なOAuthリダイレクトURIにhttps://127.0.0.1:3000/users/auth/facebook/callback(127.0.0.1:3000にはprodction用のurl)
Oauthの設定
プロバイダーの宣言
config/initializers/devise.rbでプロバイダーのkeyとsecret_keyを設定します。
Devise.setupdo|config|config.omniauth:facebook,'App ID','App Secret'config.omniauth:twitter,'API key','API secret'end私の場合ローカルで繋がったのが確認出来るまでは直接書いちゃってます。
注意としてここに書いたままで、 githubなどのリモートリポジトリーにあげないこと。
上げるときは、dotenv、figaro、credentials.yml.encなどで管理してください。
userモデルにメソッドを追加
classUser<ApplicationRecord# Include default devise modules. Others available are:# :confirmable, :lockable, :timeoutable, :trackable and :omniauthabledevise:database_authenticatable,:registerable,:recoverable,:rememberable,:validatable,:omniauthable# このから下を追加--------------------------------------------------------------defself.from_omniauth(auth)where(provider:auth.provider,uid:auth.uid).first_or_createdo|user|user.provider=auth.provideruser.uid=auth.uiduser.name=auth.nameuser.email=auth.info.emailuser.password=Devise.friendly_token[0,20]# ランダムなパスワードを作成user.image=auth.info.image.gsub("_normal","")ifuser.provider=="twitter"user.image=auth.info.image.gsub("picture","picture?type=large")ifuser.provider=="facebook"endendendこのメソッドはprovideranduidフィールドで既存のユーザーを見つけようとします。ユーザーが見つからない場合は、ランダムなパスワードといくつかの追加情報を使用して新しいユーザーが作成されます。 後ろにくっついているfirst_or_createメソッドにそのような機能があるみたいです。
emailはdeviseでユーザーを登録する時に必ず、必要なので追加してます。
imageについてはそのまま登録してしまうと画像が荒くなってしまいます。
twitterに関してはgsubメソッドを使用してurlの"_normai"を""に置き換えてます。
facebookに関してはgsubメッソドを使用してurlの"picture"を"picture?type=large"に置き換えてます。
また、carrierwaveを使ってアップローダーを挟みたい場合、画像の保存先をuser.imageからuser.remote_image_urlに変更したらアップローダー経由でimageを保存できます。(ローカルでしか試していません)
コールバックの設定
どのコントローラーでOmniauthコールバックを実装するかをDeviseに伝える必要があります。
Rails.application.routes.drawdorootto:"home#index"devise_for:users,controllers:{omniauth_callbacks:'users/omniauth_callbacks'}end今回はcontrollers/users/omniauth_callbacksでコールバックを実装します。
なので次にusersの中にomniauth_callbacks コントローラーを作成します。
classUsers::OmniauthCallbacksController<Devise::OmniauthCallbacksControllerdeffacebook# You need to implement the method below in your model (e.g. app/models/user.rb)@user=User.from_omniauth(request.env["omniauth.auth"])if@user.persisted?sign_in_and_redirect@user,event: :authentication#this will throw if @user is not activatedset_flash_message(:notice,:success,kind:"Facebook")ifis_navigational_format?elsesession["devise.facebook_data"]=request.env["omniauth.auth"].except("extra")redirect_tonew_user_registration_urlendenddeftwitter# You need to implement the method below in your model (e.g. app/models/user.rb)@user=User.from_omniauth(request.env["omniauth.auth"])if@user.persisted?sign_in_and_redirect@user,event: :authentication#this will throw if @user is not activatedset_flash_message(:notice,:success,kind:"Twitter")ifis_navigational_format?elsesession["devise.twitter_data"]=request.env["omniauth.auth"].except("extra")redirect_tonew_user_registration_urlendenddeffailureredirect_toroot_pathendendコールバックはプロバイダと同じ名前のアクションとして実装する必要があります。(今回はtwitterとfacebook)
ここでuserモデルで作成したself.from_omniauthメソッドを使って、引数にrequest.env["omniauth.auth"]をセットしてます。request.env["omniauth.auth"]の中に受け取ったユーザーのデータが入ってるみたいです。
persisted?メソッドでデータベースに@userのデータがあるかないかで条件分岐してます。
リンクについて
ログインへのリンクはdeviseで勝手に生成されています。
追加した:omniauthableのおかげみたい。
<%= render "devise/shared/links" %>
このコードが書いてあるログインとサインアップ画面に出てると思います。
classUser<ApplicationRecord# Include default devise modules. Others available are:# :confirmable, :lockable, :timeoutable, :trackable and :omniauthabledevise:database_authenticatable,:registerable,:recoverable,:rememberable,:validatable,:omniauthable# これです。end実際に出現しているリンクが以下のリンクです。
<%-ifcontroller_name!='sessions'%><%=link_to"Log in",new_session_path(resource_name)%><br/><%end%><%-ifdevise_mapping.registerable?&&controller_name!='registrations'%><%=link_to"Sign up",new_registration_path(resource_name)%><br/><%end%><%-ifdevise_mapping.recoverable?&&controller_name!='passwords'&&controller_name!='registrations'%><%=link_to"Forgot your password?",new_password_path(resource_name)%><br/><%end%><%-ifdevise_mapping.confirmable?&&controller_name!='confirmations'%><%=link_to"Didn't receive confirmation instructions?",new_confirmation_path(resource_name)%><br/><%end%><%-ifdevise_mapping.lockable?&&resource_class.unlock_strategy_enabled?(:email)&&controller_name!='unlocks'%><%=link_to"Didn't receive unlock instructions?",new_unlock_path(resource_name)%><br/><%end%><!-- --------この部分のコードです。------------------------------------------- --><%-ifdevise_mapping.omniauthable?%><%-resource_class.omniauth_providers.eachdo|provider|%><%=link_to"Sign in with#{OmniAuth::Utils.camelize(provider)}",omniauth_authorize_path(resource_name,provider)%><br/><%end%><%end%><!-- -------------ここまで----------------------------------------------------- -->
適当で申し訳ないですが、こんな感じでリンクが出ます。
ここまで実装しますと、twitterとfacebookでログインが出来るようになります。
編集ページについて
deviseはデフォルトで編集時にパスワードが必要になります。
twitter、facebookでログインするとこの場合はパスワードをランダムで生成してログインしているため、パスワードを把握しておらず、編集が出来ないと思います。
そこで編集時にパスワードを入力をしないでいいように編集します。(ただし、パスワードの変更はそのページでは出来なくなります)
私もなんでこうなるのかとか曖昧ですのでこちらを読んでもらえると助かります。
参考リンク↓
github-devise-wiki How To: Allow users to edit their account without providing a password
ルートの作成
Rails.application.routes.drawdorootto:"home#index"devise_for:users,controllers:{omniauth_callbacks:'users/omniauth_callbacks',registrations:'registrations'}# registrations: 'registrations' を追加してます。resources:users,only:[:index,:show]endコントローラーの作成
上のルートに合わせてコントローラーを作成します。(生身はサイトのコピーです)
classRegistrationsController<Devise::RegistrationsControllerprotecteddefupdate_resource(resource,params)resource.update_without_password(params)endendupdate_resourceメソッドをオーバーライドして、アップデート時のパスワード入力を取り除きました。
devise/registrations/edit.html.erbにcurrent_password(変更時に入力するパスワードのフォーム)が残っているため取り除きます。
<h2>Edit<%=resource_name.to_s.humanize%></h2><%=form_for(resource,as:resource_name,url:registration_path(resource_name),html:{method: :put})do|f|%><%=render"devise/shared/error_messages",resource:resource%><divclass="field"><%=f.label:name%><br/><%=f.text_field:name,autofocus:true,autocomplete:"name"%></div><divclass="field"><%=f.label:email%><br/><%=f.email_field:email,autocomplete:"email"%></div><divclass="field"><%=f.label:image%><br/><%=f.file_field:image%></div><%ifdevise_mapping.confirmable?&&resource.pending_reconfirmation?%><div>Currently waiting confirmation for:<%=resource.unconfirmed_email%></div><%end%><divclass="field"><%=f.label:password%><i>(leave blank if you don't want to change it)</i><br/><%=f.password_field:password,autocomplete:"new-password"%><%if@minimum_password_length%><br/><em><%=@minimum_password_length%> characters minimum</em><%end%></div><divclass="field"><%=f.label:password_confirmation%><br/><%=f.password_field:password_confirmation,autocomplete:"new-password"%></div><!-- -----------この部分を取り除きます--------------------------------------------- --><divclass="field"><%=f.label:current_password%><i>(we need your current password to confirm your changes)</i><br/><%=f.password_field:current_password,autocomplete:"current-password"%></div><!-- -----------この部分を取り除きます--------------------------------------------- --><divclass="actions"><%=f.submit"Update"%></div><%end%><h3>Cancel my account</h3><p>Unhappy?<%=button_to"Cancel my account",registration_path(resource_name),data:{confirm:"Are you sure?"},method: :delete%></p><%=link_to"Back",:back%>これで完了です。このフォームではパスワードは変更出来なくなっているので、そっちも消していいと思います。
キーとシークレットキーの管理について(credentials.yml.enc)
今回はcredentials.yml.encを使って行きます。
細かいところはこちらへ↓
Rails5.2から追加された credentials.yml.enc のキホン-Qiita
$ EDITOR="vi"bin/rails credentials:editEDITORを指定してください。今回はvimです。
以下の記述を追加します。ご自身のkeyとserect_keyを記述してください。
facebook: key: "App ID" secret: "App Secret"twitter: key: "API key" secret: "API secret"credentials.yml.encファイル自体の中身が暗号化されてしまうため、参照するには以下のコマンドで入力する必要があります。
$ rails credentials:showまた、値は以下のコマンドで参照出来ます。(コンソールで試してみます)
irb(main):001:0>Rails.application.credentials.facebook=>{:key=>AppID,:secret=>"App Secret"}irb(main):002:0>Rails.application.credentials.facebook[:key]=>AppIDirb(main):003:0>上のコードを参考にconfig/initializers/devise.rbを書き換えます。
Devise.setupdo|config|config.omniauth:facebook,Rails.application.credentials.facebook[:key],Rails.application.credentials.facebook[:secret]config.omniauth:twitter,Rails.application.credentials.twitter[:key],Rails.application.credentials.twitter[:secret]endこれで完了です。問題なくログインできると思います。(ローカル環境)
Prodction環境の設定(heroku)
アクセス用のkeyとsecret_keyを渡してあげる必要があるります。
参考サイト(詳しくはこちら)↓
secrets.ymlや環境変数をRails 5.2のEncrypted Credentialsに移行する
$ heroku config:set RAILS_MASTER_KEY=`cat config/master.key`git push heroku masterを行う前に実行してください。
先にpushするとエラーが出てしまいました。
"OmniAuth" の脆弱性対策
githubにpushするとomniauthの脆弱性を発見しましたとメールがきました。
対策として以下を参考にしました。↓
[Rails]gem "OmniAuth" の脆弱性対策-Qiita
gemの追加
gem"omniauth-rails_csrf_protection"リンクにメソッドを宣言する
リンクにmethod: :postを加えるだけです。
# 上記のコード省略<!-- --------この部分のコードです。------------------------------------------- --><%-ifdevise_mapping.omniauthable?%><%-resource_class.omniauth_providers.eachdo|provider|%><%=link_to"Sign in with#{OmniAuth::Utils.camelize(provider)}",omniauth_authorize_path(resource_name,provider),method: :post%><br/><%end%><%end%><!-- -------------ここまで----------------------------------------------------- -->その他
twitterとfacebookのアカウントが1つしかなかったため、何度も消して試してました。
以下データベースのリセットのコマンドです。
development
$ rails db:migrate:resetprodction(heroku)
$ heroku pg:reset DATABASEこのコマンドだともう一度heroku run rails db:migrateを行う必要があります。
多分もっといいコマンドがあるはず。
最後に
これでtwitterとfacebookでログインすることができます。
まだまだ、書いている途中なので、付け加えて行きます。
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme