Help us understand the problem. What is going on with this article?

[Rails] devise token auth を使う

devise token authのチュートリアルのような記事です。
大部分はこの記事を参考にしています。一部、バージョンの違い(?)によるのか、エラーが出る箇所があったため、この記事を作りました。

セットアップ

はじめにRailsアプリを作ります。

terminal
rails new devise_token_auth_test

Gemfileにdevise token auth用のgemを追記します。

Gemfile
# devise関連
gem 'devise'
gem 'devise_token_auth'

# CORS設定
gem 'rack-cors'

gem 'rack-cors'を入れる理由については公式DocsCross Origin Requests (CORS)に載っています。

bundle install した後データベースを作成します。

terminal
bundle install
rake db:create

devise token auth の導入

installします。
通常のdeviseについては、公式Docsにインストールしてくださいとは載っていませんが、rails s時にエラーが出るのでインストールします。

terminal
rails g devise:install
rails g devise_token_auth:install User auth

次に、インストール時に作成されたdb/migrate/~_devise_token_auth_create_users.rbTrackableに関するカラムを追記します。
これがないと、サインイン時にUndefined method current_sign_in_atcurrent_sign_in_atはTrackableに関するカラム)とエラーが出ます。

db/migrate/~_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 :nickname
      t.string :image
      t.string :email

      ## Tokens
      t.text :tokens

      t.timestamps
    end

    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

では、devise token auth の設定を追加します。

config/initializers/devise_token_auth.rb
DeviseTokenAuth.setup do |config|
  # リクエストごとにトークンを更新するか
  # 扱いやすいようにFalseにします
  config.change_headers_on_each _request = false

  # トークンの有効期間
  # デフォルトでは2週間です
  config.token_lifespan = 2.weeks

  # ヘッダーの名前対応
  config.headers_names = {:'access-token' => 'access-token',
                          :'client' => 'client',
                          :'expiry' => 'expiry',
                          :'uid' => 'uid',
                          :'token-type' => 'token-type' }
end

また、application_controllerに以下を追記してください。

controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include DeviseTokenAuth::Concerns::SetUserByToken
  skip_before_action :verify_authenticity_token, if: :devise_controller? # APIではCSRFチェックをしない
end

これで準備が出来ました。

試す

サーバーを起動して動かしてみましょう。

terminal
rails s

サインアップ

terminal
curl localhost:3000/api/auth -X POST -d '{"email":"example@example.com", "password":"password", "password_confirmation": "password"}' -H "content-type:application/json"

curlを使ってUserを作成するAPI(localhost:3000/api/auth)を叩いています。
引数の説明は以下の通りです。

-X POST POSTでリクエスト
-d 'foo:bar' Bodyに入れるデータ
-H 'foo:bar' ヘッダーに入れるデータ

今回は、Bodyにemailpasswordを 、ヘッダーに、Bodyの中身がjson形式であることを示すための設定content-type:application/jsonを追加しています。

サインアップに成功すると以下のようなレスポンスが返ってくるはずです。

terminal
{"status":"success","data":{"id":1,"provider":"email","uid":"example@example.com","allow_password_change":false,"name":null,"image":null,"email":"example2@example.com","created_at":"2019-05-12T20:48:24.000+09:00","updated_at":"2019-05-12T20:48:24.000+09:00"}}

サインイン

terminal
curl localhost:3000/api/auth/sign_in -X POST -d '{"email":"example@example.com", "password":"password"}' -H "content-type:application/json" -i

-iオプションを付けてレスポンスのヘッダーも表示されるようにしています。
(ここの情報をこの後使います。)

成功すると以下のようなレスポンスが返ってくるはずです。

terminal
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
Content-Type: application/json; charset=utf-8
access-token: xzTWhTURMmPdDjaKB2R9gw
token-type: Bearer
client: S2T6zY0aDB6VBXYVMdpjbg
expiry: 1558871460
uid: example@example.com
Cache-Control: no-store, must-revalidate, private, max-age=0

{"data":{"id":1,"email":"example@example.com","provider":"email","uid":"example@example.com","allow_password_change":false,"name":null,"image":null}}

パスワードの変更

terminal
curl localhost:3000/api/auth/password -X PUT -d '{"password":"password_new", "password_confirmation": "password_new"}' -H "content-type:application/json" -H "access-token: xzTWhTURMmPdDjaKB2R9gw" -H "client: S2T6zY0aDB6VBXYVMdpjbg" -H "uid: example@example.com"

パスワードの変更はPOSTではなくPUTを指定します。
また、ログイン時のレスポンスのヘッダーにあったaccess-token client uidをヘッダーに追加しています。

成功すると以下のようなレスポンスが返ってくるはずです。

terminal
{"success":true,"data":{"id":1,"provider":"email","allow_password_change":false,"email":"example@example.com","uid":"example@example.com","name":null,"image":null,"created_at":"2019-05-12T20:30:50.000+09:00","updated_at":"2019-05-12T21:31:33.000+09:00"},"message":"パスワードの更新に成功しました。"}

deviseのコントローラーを編集したい時

terminal
rails g controller api/auth/registrations
controllers/api/auth/registrations_controller.rb
class Api::Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController
  # hogehoge
end
config/routes.rb
Rails.application.routes.draw do

  namespace :api do
    mount_devise_token_auth_for 'User', at: 'auth', controllers: {
        registrations: 'api/auth/registrations'
    }
  end

end
Masahiro_T
困ったときの再起動
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした