Edited at

[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