Ruby on Rails

【Ruby on Rails】gem "devise_token_auth" を使ってネイティブアプリからの認証機能を実装

Devise と Devise Token Auth のどちらも並行して利用したいときの実装メモです。

Devise Token Auth とは?

Webの世界ではCookieを使って認証認可を実現するが、ネイティブアプリの世界ではCookieを使用することができない。

ネイティブアプリの世界ではトークンベースで認証機能を実現する。

Railsでは、Devise Token AuthというGemを使うと、トークンベースの認証を簡単に実現することができる。

Devise と併用する場合の導入手順

Gemfile に下記内容を追加して、bundle install

gem 'devise'
gem 'devise_token_auth'
gem 'rack-cors'

rails g devise:installコマンドを叩いて、表示される内容にしたがって諸々設定する

❯❯❯ rails g devise:install
Running via Spring preloader in process 47294
      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 class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

rails g devise:views コマンドを叩くと、認証に必要なViewファイルが生成される

rails g devise_token_auth:install User auth コマンドを叩く

db/migrate/YYYYMMDDHHIISS_devise_token_auth_create_users.rb を下記のように修正

class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[5.2]
  def change

    create_table(:users) do |t|
      ## Required
      t.string :provider, :null => false, :default => "email"
      t.string :uid, :null => false, :default => ""

      ## Database authenticatable
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at
      t.boolean  :allow_password_change, :default => false

      ## 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.string   :current_sign_in_ip
      t.string   :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

      ## User Info
      t.string :name
      t.string :username, null: false, default: ""
      t.string :image
      t.string :email
      t.integer :role, null: false, default: 0

      ## Tokens
      t.text :tokens

      t.timestamps
    end

    add_index :users, :username,             unique: true
    add_index :users, :email,                unique: true
    add_index :users, [:uid, :provider],     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

rails db:migrate コマンドを叩く

app/controller/application_controller.rbを以下のように編集する

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

config/application.rbRack::Cors の設定を追加する

module Hoge
  class Application < Rails::Application

    ...

    # for devise_token_auth
    config.middleware.use Rack::Cors do
      allow do
        origins '*'
        resource '/api/v1/*',
          :headers => :any,
          :expose  => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
          :methods => [:get, :post, :options, :delete, :put]
      end
    end
  end
end

config/routes.rb に以下を追加

Rails.application.routes.draw do
  devise_for :users # mount_devise_token_auth_for より先にくるように
  namespace :api do
    namespace :v1 do
      mount_devise_token_auth_for 'User', at: 'auth'
    end
  end
  ...
end

app/controllers/api/v1/application_controller.rb を以下のように修正

module Api
  module V1
    class ApplicationController < ActionController::API
      skip_before_action :verify_authenticity_token
      include DeviseTokenAuth::Concerns::SetUserByToken
    end
  end
end

下記JSONを localhost:5000/api/v1/auth/sign_in に向けてPOSTすると client, uid, access-token をレスポンスヘッダから取得できる

client, uid, access-token を次のリクエストヘッダに入れればOK

参考

-Ruby on Rails