markdown [rails:devise] Ruby on Rails的身份验证gem。 #ruby #rails
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown [rails:devise] Ruby on Rails的身份验证gem。 #ruby #rails相关的知识,希望对你有一定的参考价值。
## OVERVIEW ##
> [plataformatec/devise - github.com](https://github.com/plataformatec/devise)
> [devise - ruby.doc.info](https://www.rubydoc.info/github/plataformatec/devise/)
[warden](https://github.com/wardencommunity/warden) をベースにした Ruby on Rails のための認証管理 gem で、Rails 開発では広く一般的に利用されている。認証まわりの「よくあるやつ」を包括的に提供してくれる。
### Modules
> [[*Rails*] deviseの使い方(rails5版)](https://qiita.com/cigalecigales/items/f4274088f20832252374)
- database_authenticatable : パスワードのハッシュ登録・検証機能の提供、認証方式に POST か BASIC 認証がある
- registerable : 登録 ( サインアップ ) やユーザ自身の編集・削除を提供
- recoverable : パスワードリセット・通知の提供
- rememberable : Cookie を保存しユーザを記憶するためのトークン生成・削除を提供
- trackable : サインイン回数・時間・IP アドレスの記録を提供
- validatable : メールアドレスやパスワードのバリデーションを提供
- confirmable : 登録 → ワンタイム URL つきメール送信 → 本登録というフローや、アカウントの本登録済み検証を提供
- lockable : ログイン失敗 → ロック → メールや時間経過でロック解除といったアカウントロック機能を提供
- timeoutable : 一定時間活動していないアカウントのセッション破棄を提供
- omniauthable : omniauth との連携機能を提供
### Refs
- [定番のgem「devise」活用法 (1)](https://codezine.jp/article/detail/10813?mode=print)
- [定番のgem「devise」活用法 (2)](https://codezine.jp/article/detail/10899?mode=print)
- [devise-i18n](https://github.com/tigrish/devise-i18n)
### Install to rails
```sh
# gem のインストール
$ vi Gemfile
> gem 'devise'
$ bundle install
# devise 設定ファイルの作成
$ rails g devise:install
> create config/initializers/devise.rb # devise 設定ファイル
> create config/locales/devise.en.yml # devise 用のロケールファイル
# 利用ロケールを ( スタブでも良いので ) 用意
# @see https://qiita.com/MasatoYoshioka@github/items/8d910e793e7c485403bb
$ cp config/devise.en.yml config/devise.ja.yml
$ vi config/devise.ja.yml # 行頭 en を ja へ
# devise 設定ファイルの調整
$ vi config/initializers/devise.rb
> config.scoped_views = true # 名前空間分けに対応させる
> mailer_sender # パスワードを忘れた場合などの際に送られるメールのfromアドレスを指定
> require 'devise/orm/active_record' # deviseがサポートする ORM ( デフォルト: ActiveRecord )
> case_insensitive_keys [:email] # 大文字/小文字を区別しないカラム名を指定
> strip_whitespace_keys [:email] # 空白を除去するカラム名を指定
> password_length 6..128 # Validatable モジュール用の設定 ( パスワードの長さ指定 )
> reset_password_within 6.hours # パスワードリセットするための URL の有効期限を指定
> config.timeout_in = 30.minutes # タイムアウト時間を設定
> config.sign_out_via = :delete # ログアウトのメソッドを指定、デフォルト :delete なので :get にしたほうが無難
> if Rails.env.production? # 本番環境では Rails の secret_key_base を secret_key として利用
> config.secret_key = Rails.application.credentials.secret_key_base
> end
# Action Mailer の URL 設定をしておく
$ vi config/application.rb
> config.action_mailer.default_url_options = { host: ENV.fetch('DOMAIN') }
# views/layouts で Flash が出るようにしておく ( 以下コードは適当 )
$ vi app/views/layouts/application.html.erb
> <% if !notice.nil? %><p class="notice"><%= notice %></p><% end %>
> <% if !alert.nil? %><p class="alert"><%= alert %></p><% end %>
# devise 用のビューファイルを generate
$ rails g devise:views
# devise 用の user モデルを generate
$ rails g devise user
# rails 5 系の場合 protect_form_forgery を修正
# https://goo.gl/C7ME1e
# https://github.com/plataformatec/devise#controller-filters-and-helpers
$ vi app/controllers/application_controller.rb
> protect_from_forgery prepend: true
# コントローラは存在しない場合 devise の vendor が参照される
# 継承してカスタムしたい場合には以下で作成可能
# 作成後 routes にて controllers: {} で sessions: 'admin/sessions' とか
$ rails g devise:controllers users
# ルーティング設定
$ vi config/routes.rb
```
#### /sign_in を /login にするなどのパス調整
```rb
# config/routes.rb
devise_for :users, path_names: {
sign_up: 'signup',
sign_in: 'login',
sign_out: 'logout',
password: 'password',
confirmation: 'confirmation',
unlock: 'unlock',
registration: 'register',
}
```
#### 名前空間を分けたりルーティングをいじったり
> [devise_for](https://www.rubydoc.info/github/plataformatec/devise/master/ActionDispatch/Routing/Mapper%3Adevise_for)
> [Configuring views](https://github.com/plataformatec/devise#configuring-views)
> [Configuring controllers](https://github.com/plataformatec/devise#configuring-controllers)
> [Railsでdeviseひとつで複数モデルを管理しよう](https://qiita.com/Yama-to/items/54ab4ce08e126ef7dade)
> [Deviseでdevise_forをネストした場所に書く方法](https://www.tmp1024.com/programming/post-4661)
```rb
# config/routes.rb
# /admin/sign_in みたいなのを想定している
# この場合 :authenticate_user! メソッドは :authenticate_admin_user! となる
namespace :admin do
devise_for :users, path: ''
end
```
```sh
# views を作成
$ rails g devise:views admin
# ( 必要ならば ) カスタム用 controller も領域を区切って作成
$ rails g devise:controllers admin
```
#### 既存 User モデルに適用する場合
```rb
# config/routes.rb にてルーティングを追加
devise_for :users
__END__
# カスタムしたい場合は以下を参考に ...
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
```
```rb
# user.rb 定義内にて devise にて利用モジュールを追加
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
```
```rb
# users のマイグレーションを以下を参考に書き換え
# generate で生成される db/migrate/00000000000000_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.inet :current_sign_in_ip
t.inet :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
```
### How to use?
> [Controller filters and helpers](https://github.com/plataformatec/devise#controller-filters-and-helpers)
> [ログイン後にマイページに飛ばす](http://tsumazuki.hatenadiary.jp/entry/2013/08/15/033130)
因みに `current_user` は当たり前だけどコントローラ / ビュー層でしか使えないからね。
```rb
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# フィルターで「認証検査」して :only で認証領域を限定
before_action :authenticate_user!, only: :index
def index
# current_user にログイン済みユーザが入る
# admin とかプレフィクスつけたら current_admin_user とかになる
@user = current_user
end
# ログイン後にここにいけ
# application_controller.rb の継承先に書いても効かない注意ので注意
# モデルやロール毎に振り分けたい場合はここで分岐頑張るしかない
protected def after_sign_in_path_for(resource)
if resource == :admin_user
admin_root_path
else
root_path
end
end
# ログアウトしたらにここにいけ
protected def after_sign_out_path_for(resource)
if resource == :admin_user # ログアウト時 resource には :user とかのシンボルがはいる
new_admin_user_session_path
else
new_user_session_path
end
end
end
```
```erb
<!--
devise によるログインや登録、ユーザ編集などのフォームでは
devise_error_messages! メソッドでエラー内容が出力できる
-->
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
...
```
```erb
<!-- よくあるログインしてたら ~ でしてなかったら ~ というやつ -->
<% if user_signed_in? %>
<%= link_to 'logout', destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to 'sign up', new_user_registration_path %>
<%= link_to 'login', new_user_session_path %>
<% end %>
```
#### Mailer
> [How To: Use custom mailer](https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer)
> [rodrigoflores/multiple-mailer](https://github.com/rodrigoflores/multiple-mailer/blob/master/app/models/user.rb#L6)
> [Rails Devise でパスワードリセットなどのメールテンプレート(Mailer ビュー)をカスタマイズ](https://easyramble.com/customize-mail-template-of-devise.html)
デフォルトのままだと `Devise::Mailer` で送った URL はスコープ対応してくれないファック。
```rb
# config/initializers/devise.rb
config.mailer = 'UsersMailer'
config.parent_mailer = 'ApplicationMailer'
```
```rb
# app/mailers/users_mailer.rb
class UsersMailer < Devise::Mailer
helper :application
include Devise::Controllers::UrlHelpers
default template_path: 'users_mailer'
# def confirmation_instructions(record, token, opts={})
# super
# end
# def email_changed(record, token, opts={})
# super
# end
# def password_change(record, token, opts={})
# super
# end
# def reset_password_instructions(record, token, opts={})
# super
# end
# def unlock_instructions(record, token, opts={})
# super
# end
end
```
```erb
<!-- app/views/users_mailer/reset_password_instructions.html.erb -->
<!--
オーバライドしたいビューを作成してカスタム
$ rails g devise:views で作ったビューでは複数スコープに対応していないため
以下の link_to に入る URL メソッドは edit_password_url だが、ここで
edit_users_user_password_url とか edit_admin_user_password_url とかに変更すれば
スコープを考慮した URL を吐いてくれる
confirmation_url は admin_user_confirmation_url(nil, ...) で動いた
user_hoge_url メソッドは既に古い実装のようで @resource を食わせると変な URL 吐くので
第一引数を nil にするのがポイント
-->
<% if @resource.is_admin %>
<%= link_to 'Change my password', edit_admin_user_password_url(nil, reset_password_token: @token) %>
<% else %>
<%= link_to 'Change my password', edit_user_password_url(nil, reset_password_token: @token) %>
<% end %>
```
```yml
# config/locales/devise.en.yml
en:
devise:
# メール件名のロケールはこのへん
# 本文とかもここに body: とかで突っ込むとよいかも
mailer:
confirmation_instructions:
subject: "Confirmation instructions"
reset_password_instructions:
subject: "Reset password instructions"
unlock_instructions:
subject: "Unlock instructions"
email_changed:
subject: "Email Changed"
password_change:
subject: "Password Changed"
```
#### SessionsController
> [Module: Devise::Controllers::SignInOut](https://www.rubydoc.info/github/plataformatec/devise/Devise/Controllers/SignInOut)
ユーザが `role` カラムや関連モデルを持っていて email ( unique id ) + password 以外のログイン検査が必要な場合は SessionsController で各メソッドをオーバライドしてあげる。
```rb
# app/controllers/admin/sessions_controller.rb
class Admin::SessionsController < Devise::SessionsController
before_action :verify_admin_user, only [:create]
protected def verify_admin_user
if current_admin_user.role != 'admin'
sign_out_all_scopes current_admin_user # 手動ログアウト
flash[:alert] = t 'devise.failure.invalid', authentication_keys: :email
return redirect_to new_admin_user_session_url # ログイン画面へ行け
end
end
end
```
#### RegistrationsController
> [deviseを使ってUserモデルに一対一のリレーションシップでユーザー情報を紐付け](https://qiita.com/chokosuki4400/items/30340d149c7cb7abf41b)
> [devise_parameter_sanitizer.permit](devise_parameter_sanitizer.permit)
> [Rails Devise registration with an additional model](https://stackoverflow.com/questions/13670013/rails-devise-registration-with-an-additional-model?answertab=votes#tab-top)
登録処理周りは registrations_controller が担当している。初期値の入れ込み、子モデルの同時登録、リダイレクト先変更など、案件によってカスタムしないとならない場所。以下は `user` モデルの新規作成時には、同時に `company` のような子モデルを登録する必要があるケースを考慮 ( このあたりのアソシエーションやバリデーション設定は済んでいる前提 )。
```rb
# registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
# devise デフォルトの user モデルカラム ( provider や email など ) 以外に
# user モデルにカラム、同時登録する子モデル ( company ) がある場合は
# before_action フィルタへのカスタムメソッドを登録してごにょごにょする
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
def new
resource = build_resource({})
resource.build_company # user.company.build みたいなことみたい
resource.company.plan_id = Plan.where({name: 'free'}).first.id
respond_with resource
# ここでいう resource は user モデルと思ってよい
# new のフォームに流す初期値セットなんかはこのへんで
end
# edit / update / destroy /cancel など必要なら同じ要領でオーバライド
# def edit
# super
# end
#
# def update
# super
# end
#
# def destroy
# super
# end
#
# def cancel
# super
# end
# Sign up 時に同時登録するカラム・子モデルを追加設定
# 必要なカラム全て設定しないと登録されたような挙動で DB に NULL が入ってしまう
protected def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up) do |params|
params.permit(
:name, :email, :password, :password_confirmation,
company_attributes: [
:user_id, :plan_id, :name, :address, :email,
:phone, :website, :country, :history
]
)
end
end
# こっちは更新時
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update) do |params|
params.permit(
:name, :email, :password, :password_confirmation, :current_password,
company_attributes: [
:user_id, :plan_id, :name, :address, :email,
:phone, :website, :country, :history
]
)
end
end
# Sign up 完了時の遷移先
# confirmable 時はこちらではなく confirmations_controller の方が優先される
# また Sign up 完了時点では認証領域外 ( ログイン画面とか ) に飛ばす思想みたいで
# 自動ログインとかはしてくれない ... あたり前か
def after_sign_up_path_for(resource)
# super(resource)
root_path
end
# Sign up → メール confirm 前など非アクティブ時点の遷移先
def after_inactive_sign_up_path_for(resource)
# super(resource)
new_user_session_path
end
# 更新処理後のリダイレクト先
def after_update_path_for(resource)
root_path
end
end
```
```rb
# models/user.rb
# fields_for を使うのでネストを許可
accepts_nested_attributes_for :company
```
```rb
<%= f.fields_for :company do |cf| %>
<div class="form-group">
<%= cf.label :name %>
<%= cf.text_field :name, class: 'form-control', required: true %>
</div>
<% end %>
```
------
## OAUTH ##
> [omniauth/omniauth - github.com](https://github.com/omniauth/omniauth)
[OAuth](https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be) のための gem である omniauth と連携設定をすることで、各種 WEB サービスと連携した OAuth 認証が実現できる。
### Refs
- [定番gem「OmniAuth」活用法](https://codezine.jp/article/detail/10970?mode=print)
- [RailsでいろんなSNSとOAuth連携/ログインする方法](https://qiita.com/awakia/items/03dd68dea5f15dc46c15)
- [OmniAuthによるTwitter/FacebookのOAuth認証を実装](https://qiita.com/wtb114/items/a617474f1d31fa9e7c53)
- [deviceなしで Google OAuth 認証のサインインの実装](https://qiita.com/daijiro_maeyama/items/8b672ec0721d43f2d044)
### Install
`admin` 名前空間における `user` モデルの Facebook との OAuth を想定。
```sh
$ vi Gemfile
> gem 'omniauth'
> gem 'omniauth-facebook'
$ bundle install
# user に provider と uid を追加 ( ユーザ名なども取れるので必要ならば追加 )
$ rails g migration AddColumnsToUsers provider:string uid:string
$ rake db:migrate
# .env に連携サービスに登録したアプリの ID / Secret を追加
$ vi .env
> FACEBOOK_APP_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> FACEBOOK_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# devise.rb に omniauth 連携設定を追加
$ vi config/initializers/devise.rb
> config.omniauth :facebook,
> ENV.fetch('FACEBOOK_APP_ID'), ENV.fetch('FACEBOOK_APP_SECRET'),
> scope: 'email' # 外部アカウントから取得したい情報の権限設定 ( サービスにより異なる )
# API からのリダイレクトを受け付けるコントローラを生成
$ rails g devise:controllers users
> ...
> create app/controllers/users/omniauth_callbacks_controller.rb # こいつが API コールバック用
# devise の omniauth を user モデルに割り当て & ルーティング設定
# モデルは既存の :database_authenticatable の後に追加すれば OK
$ vi app/models/user.rb
> devise :omniauthable, omniauth_providers: [:facebook]
# ルーティングで devise_for :users にしたならもうルーティングされてるかも
$ vi app/config/routes.rb
$ rake routes # 確認して /users/auth/facebook /users/auth/facebook/callback があれば OK
```
#### Link view
ログインボタンのビューを調整。各 SNS サービスで JavaScript による [ログインボタン - Facebook](https://developers.facebook.com/docs/facebook-login/web/login-button?locale=ja_JP) みたいなのが公開されているので、そっちを使う手段もある。但しその場合は自分で devise との連携を考えないといけないのでこっちのが楽。
```erb
# app/views/shared/_links.html.erb
# omniauth_authorize_path メソッドを修正 ( 名前空間を区切ったりすると修正が必要ぽい )
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%=
link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}",
public_send("admin_user_#{provider.to_s}_omniauth_authorize_path")
%>
<br />
<% end -%>
<% end -%>
```
#### User Model
```rb
# models/user.rb
class User < ApplicationRecord
# 認証時にコールされる find_or_create_for_oauth メソッドをオーバライドしてカスタム
def self.find_or_create_for_oauth(auth)
find_or_initialize_by email: auth.info.email do |user|
if user.persisted?
return user
# 既存ユーザなら user を変更せず return してブロックを中断
end
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
# 新規ユーザなら OAuth で返却された情報をセット
# このタイミングで password までセットして即ログインさせる手もある
# 但しその場合当該ユーザへのパスワード通知どうする問題がある
# また confirmable: true にしている場合メールアドレス登録処理が挟まる
# この段階ではパスワード未セットで、後にフォーム入力を挟む方が無難な気がする
end
end
def self.new_with_session(params, session)
if user_attributes = session['devise.user_attributes']
new(user_attributes) { |user| user.attributes = params }
else
super
end
end
end
```
#### Callback Controller
```rb
# omniauth_callbacks_controller.rb
# OAuth 認証処理をカスタム
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Facebook からのコールバックを有効化
def facebook
callback
end
# 各サービスで共通利用するコールバックメソッドを定義
private def callback
@user = User.find_or_create_for_oauth(request.env['omniauth.auth'])
# 上記 request.env['omniauth.auth'] にサービスから提供されたユーザ情報が入る
if @user.new_record?
session['devise.user_attributes'] = @user.attributes
redirect_to new_admin_user_registration_url
# 新規なら find_or_initialize_by で new した空ユーザモデルを session にセット
# 登録フォームリダイレクト → ここまでにセットした値がビュー form_helper に反映される
# 追加でパスワードやユーザ関連子モデルの情報入力をさせて create へ POST で登録完了
else
sign_in_and_redirect @user
# 既存ユーザならログイン実行 & リダイレクト
end
end
end
```
### ルーティングの手動設定
> [Wrong OmniAuth configuration. If your are getting this exception... message](https://github.com/omniauth/omniauth-saml/issues/129)
> [Devise+Omniauth, routes versioning](https://stackoverflow.com/questions/24574094/deviseomniauth-routes-versioning)
> [deviseでOAuth認証後のログイン先を変更する方法](https://notsleeeping.com/archives/2487)
users が複数ロールを兼ねていて `has_one :admins` だったり `has_one :members` だったりするような構成で、 devise で複数の `namespace` に跨った認証を実装しているようなケース ( `current_admin_user` とか `current_user` とかの devise scope が存在するようなケース ) において、omniauth 連携箇所についてだけは **必ずモデルに対して単一のルーティング ( URI ) しか設けられない** 点に注意。またコールバック受け時の実処理を記載するコントローラ `omniauth_callbacks` もモデルに対して 1 つしか実装できない。
よって通常ユーザ `/users` と管理者ユーザ `/admin/users` のようなルーティングを実装していたとしても omniauth による OAuth コールバック処理は同居させる必要がある。実際に `routes.rb` にて `:omniauthable` なモデルへ複数の `omniauth_callback` ルーティングを設定しようとすると以下のようなエラーになる。
```
`set_omniauth_path_prefix!': Wrong OmniAuth configuration. If you are getting this exception, it means that either: (RuntimeError)
1) You are manually setting OmniAuth.config.path_prefix and it doesn't match the Devise one
2) You are setting :omniauthable in more than one model
3) You changed your Devise routes/OmniAuth setting and haven't restarted your server
```
このような場合は `devise_for` によるルーティングのうち `:omniauth_callbacks` を `skip` して手動でルーティングしてあげる必要がある。
```rb
# config/routes.rb
# Manually setting for omniauth callbacks.
devise_for :users, path: '/',
path_names: {
sign_up: 'signup',
sign_in: 'login',
sign_out: 'logout',
password: 'password',
unlock: 'unlock',
registration: 'register',
confirmation: 'confirmation',
},
controllers: {
omniauth_callbacks: 'omniauth_callbacks', # こいつを user / admin で共用
confirmations: 'confirmations',
passwords: 'passwords',
registrations: 'registrations',
sessions: 'sessions',
}
# Admin layer.
namespace :admin do
devise_for :users, skip: [:omniauth_callbacks] # 既に共用があるので skip する
end
```
```rb
# config/initializers/devise.rb
# Manually setting for omniauth callbacks.
config.omniauth_path_prefix = '/auth'
```
```erb
<!-- _links.html.erb -->
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%=
link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}",
public_send("user_#{provider.to_s}_omniauth_authorize_path"),
onclick: "document.cookie = 'role=admin; path=/'" # コールバックで利用
%>
<br />
<% end -%>
<% end -%>
```
```rb
# app/controllers/omniauth_callbacks_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
@user = User.find_or_create_for_oauth(request.env['omniauth.auth'])
if @user.new_record?
# 適当に OAuth ログインボタンの onClick に Cookie セットとか仕込んで
# このタイミングで user なのか admin なのかでリダイレクト先を切り分け
# 恐らくリダイレクト先は新規登録なので new_user_registration_url みたいなやつ
else
# こちらはそのままログインさせる分岐だが、sign_in_and_redirect に引数を渡さないで
# スコープを自動判別させた場合、このままだと全てのロールが同じ user スコープになる
# ( admin だろうが user だろうが全て current_user などの扱いになってしまう )
# よって上記と同様に Cookie などで事前にどの分岐から来たのか印をつけておき
# 、このタイミングで「どのスコープでログインさせるか」を手動で設定させるのがよい
case cookies.fetch('role')
when 'admin'
cookies.delete('role')
sign_in(:admin_user, @user)
redirect_to after_sign_in_path_for(@user) # スコープありな admin_user
else
cookies.delete('role')
sign_in_and_redirect @user # スコープなし user
end
end
end
end
```
```sh
$ rails routes
Prefix Verb URI Pattern Controller#Action
root GET / feeds#root
new_user_session GET /login(.:format) sessions#new
user_session POST /login(.:format) sessions#create
destroy_user_session GET /logout(.:format) sessions#destroy
user_facebook_omniauth_authorize GET|POST /auth/facebook(.:format) omniauth_callbacks#passthru
user_facebook_omniauth_callback GET|POST /auth/facebook/callback(.:format) omniauth_callbacks#facebook
new_user_password GET /password/new(.:format) passwords#new
edit_user_password GET /password/edit(.:format) passwords#edit
user_password PATCH /password(.:format) passwords#update
PUT /password(.:format) passwords#update
POST /password(.:format) passwords#create
cancel_user_registration GET /register/cancel(.:format) registrations#cancel
new_user_registration GET /register/signup(.:format) registrations#new
edit_user_registration GET /register/edit(.:format) registrations#edit
user_registration PATCH /register(.:format) registrations#update
PUT /register(.:format) registrations#update
DELETE /register(.:format) registrations#destroy
POST /register(.:format) registrations#create
new_user_confirmation GET /confirmation/new(.:format) confirmations#new
user_confirmation GET /confirmation(.:format) confirmations#show
POST /confirmation(.:format) confirmations#create
new_admin_user_session GET /admin/login(.:format) admin/sessions#new
admin_user_session POST /admin/login(.:format) admin/sessions#create
destroy_admin_user_session GET /admin/logout(.:format) admin/sessions#destroy
new_admin_user_password GET /admin/password/new(.:format) admin/passwords#new
edit_admin_user_password GET /admin/password/edit(.:format) admin/passwords#edit
admin_user_password PATCH /admin/password(.:format) admin/passwords#update
PUT /admin/password(.:format) admin/passwords#update
POST /admin/password(.:format) admin/passwords#create
cancel_admin_user_registration GET /admin/register/cancel(.:format) admin/registrations#cancel
new_admin_user_registration GET /admin/register/signup(.:format) admin/registrations#new
edit_admin_user_registration GET /admin/register/edit(.:format) admin/registrations#edit
admin_user_registration PATCH /admin/register(.:format) admin/registrations#update
PUT /admin/register(.:format) admin/registrations#update
DELETE /admin/register(.:format) admin/registrations#destroy
POST /admin/register(.:format) admin/registrations#create
new_admin_user_confirmation GET /admin/confirmation/new(.:format) admin/confirmations#new
admin_user_confirmation GET /admin/confirmation(.:format) admin/confirmations#show
POST /admin/confirmation(.:format) admin/confirmations#create
```
以上是关于markdown [rails:devise] Ruby on Rails的身份验证gem。 #ruby #rails的主要内容,如果未能解决你的问题,请参考以下文章
Rails:如何在 Rails 中为 Devise 设置密钥?
无法在 Rails 中使用 Devise 销毁会话 [重复]
Heroku/Rails/Devise:你想要的改变被拒绝了