devise token authのチュートリアルのような記事です。
大部分はこの記事を参考にしています。一部、バージョンの違い(?)によるのか、エラーが出る箇所があったため、この記事を作りました。
セットアップ
はじめにRailsアプリを作ります。
rails new devise_token_auth_test
Gemfileにdevise token auth用のgemを追記します。
# devise関連
gem 'devise'
gem 'devise_token_auth'
# CORS設定
gem 'rack-cors'
gem 'rack-cors'
を入れる理由については公式DocsのCross Origin Requests (CORS)に載っています。
bundle install した後データベースを作成します。
bundle install
rake db:create
devise token auth の導入
installします。
通常のdeviseについては、公式Docsにインストールしてくださいとは載っていませんが、rails s
時にエラーが出るのでインストールします。
rails g devise:install
rails g devise_token_auth:install User auth
次に、インストール時に作成されたdb/migrate/~_devise_token_auth_create_users.rb
にTrackable
に関するカラムを追記します。
これがないと、サインイン時にUndefined method current_sign_in_at
(current_sign_in_at
はTrackableに関するカラム)とエラーが出ます。
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 の設定を追加します。
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
に以下を追記してください。
class ApplicationController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
skip_before_action :verify_authenticity_token, if: :devise_controller? # APIではCSRFチェックをしない
end
これで準備が出来ました。
試す
サーバーを起動して動かしてみましょう。
rails s
サインアップ
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にemail
・password
を 、ヘッダーに、Bodyの中身がjson形式であることを示すための設定content-type:application/json
を追加しています。
サインアップに成功すると以下のようなレスポンスが返ってくるはずです。
{"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"}}
サインイン
curl localhost:3000/api/auth/sign_in -X POST -d '{"email":"example@example.com", "password":"password"}' -H "content-type:application/json" -i
-i
オプションを付けてレスポンスのヘッダーも表示されるようにしています。
(ここの情報をこの後使います。)
成功すると以下のようなレスポンスが返ってくるはずです。
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}}
パスワードの変更
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
をヘッダーに追加しています。
成功すると以下のようなレスポンスが返ってくるはずです。
{"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のコントローラーを編集したい時
rails g controller api/auth/registrations
class Api::Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController
# hogehoge
end
Rails.application.routes.draw do
namespace :api do
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
registrations: 'api/auth/registrations'
}
end
end