新たに立ち上げるサービスをAPIとフロントを完全に分けて作る事になった。
自力で認証システムを作ることも考えたが、パスワード再発行やメール認証など定番の処理を0から実装する手間と、
保守上の観点からdevise token authとomniauthを使って立ち上げる際になかなか詰まったのでメモ。
手順
Deviseをインストール
Gemfileに以下を追加。
gem 'devise_token_auth'
その上で以下を実行。(認証をかけるモデルがUserの場合)
$ bundle exec rails g devise:install
$ bundle exec rails g devise_token_auth:install User auth
作られたmigrationファイル(*_devise_token_auth_create_users.rbなど)に以下を追加。
## 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
これ、ドキュメントのどこにも書いてないがomniauthを使い二回目以降にログインすると
NoMethodError: undefined method 'current_sign_in_at' for User
が出てしまう。trackableが使われているか不明だが、とりあえず全部追加した。
今回は、omniauthを使うのでapp/models/user.rbのomniauthableを追加。
また、メールの存在確認のための認証を入れる予定なのでconfirmableも追加した。
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :omniauthable
以下をdevelopment.rbに追加。
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
Omniauth + Omniauth Twitterを追加
Gemfileに以下を追加
gem 'omniauth-twitter'
以下のファイルをconfig/initializers/omniauth.rbに作成。
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, ENV["TWITTER_KEY"], ENV["TWITTER_SECRET"]
end
更に、config/application.rbに以下を追加
config.session_store :cookie_store, key: '_<<<アプリケーション名>>>_session'
config.middleware.use ActionDispatch::Cookies # Required for all session management
config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
これは、RailsのAPIモードだとセッション管理のミドルウェアが入らないから。
一方でomniauthはデフォで使うのでとりあえず設定しておく。
render template を有効にする
RailsのAPI modeだとrender json:以外が描画されないため、devise token authのoauthが使えない。
その為、以下のようにコントローラをオーバーライドしてerbを描画できるようにする。
これはdevise token authのバグなのか、設定ミスでこれが必要になっているのかはわからない。
app/controllers/users/omniauth_callbacks_controller.rbに以下の内容でファイルを作成する。
class Users::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCallbacksController
include ActionView::Rendering
end
その後、routesを以下のように修正する。(認証をかけるモデルがUserの場合)
Rails.application.routes.draw do
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
omniauth_callbacks: "users/omniauth_callbacks"
}
end
TIPS
devise installしないとそもそも動かない
devise token authの公式サイトにはdeviseをwrapしているから不要っぽく書いてあるが、
devise installをしないと最初から下記のエラーが出てしまう。
NoMethodError: undefined method `devise' for User (call 'User.connection' to establish a connection):Class