devise_token_authを導入してみる

# deviseとは
Ruby on Railsで簡単に認証機能を実装することができるgem。
deviseを利用することで、ログイン、サインアップなどの認証を簡単に行うことができる。

# devise_token_authとは
トークン認証機能を実装するためのgem。
認証が必要な操作を行う際に、HTTPリクエストのheader情報にユーザーの認証情報であるトークンを付与し、バックエンド側（Ruby on RailsのAPI）に送ります。
基本的にはサーバーで認証の状態管理はせず、送られて来たTokenを検証することで処理を安全に行うことができる。

参考 : https://magazine.techcareer.jp/technology/skill/11273/
公式Docs https://devise-token-auth.gitbook.io/devise-token-auth/

# devise_token_authのセットアップ

devise_token_authを使うときは、deviseも一緒にインストールしないと、
 `rails s` 時にエラーが出るので注意。

```Gemfile
gem 'devise', '~> 4.8'
gem 'devise_token_auth', '~> 1.1', '>= 1.1.5'
```
Gemをインストール

```terminal
bundle install
```
deviseとdevise_token_authの初期化

```terminal
bundle exec rails g devise:install
bundle exec rails g devise_token_auth:install User auth
```

成功すると、下記のように表示される。

```terminal
create  config/initializers/devise_token_auth.rb
insert  app/controllers/application_controller.rb
  gsub  config/routes.rb
create  db/migrate/20210607143435_devise_token_auth_create_users.rb
create  app/models/user.rb
```

今回は名前、メール、パスワードで認証させるため、不要なものはコメントアウト。

>`Recoverable`・`Rememberable`・`Confirmable` 関連のコードや、
`User Info`の`nickname`と`image`も使用しないため、コメントアウトします。
`add_index :users, :confirmation_token, unique: true`はコメントアウトせずにマイグレーションを実行すると、後々エラーになるので注意。

```db/migrate/~_devise_token_auth_create_users.rb
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.0]
  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

      ## 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

```
usersテーブルの作成完了

```terminal
bundle exec rails db:migrate
```
```
== 20211108044339 DeviseTokenAuthCreateUsers: migrating =======================
-- create_table(:users)
   -> 0.0028s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0011s
-- add_index(:users, [:uid, :provider], {:unique=>true})
   -> 0.0010s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0010s
== 20211108044339 DeviseTokenAuthCreateUsers: migrated (0.0067s) ==============
```

```config/initializers/devise_token_auth.rb
DeviseTokenAuth.setup do |config|
  # リクエストごとにtokenを新しくするか設定
  ## ======= コメントを外し、falseに変更 =======
  config.change_headers_on_each_request = false

  # ...省略

  # tokenの有効期間を２週間に設定
  ## ======= コメントを外す =======
  config.token_lifespan = 2.weeks

  # ...省略

  # 認証用ヘッダーの名前の定義
  ## ================== コメントを外す ===================
  config.headers_names = {:'access-token' => 'access-token',
                         :'client' => 'client',
                         :'expiry' => 'expiry',
                         :'uid' => 'uid',
                         :'token-type' => 'token-type' }
end

```

# CORSの設定

CORSとは
> Cross Origin Resource Sharingの略。
CORSは、「同一生成元ポリシー(Same-Origin Policy)」を一部解除し、
異なるオリジン間でリソースを共有できるようにするための仕組み。

「同一生成元ポリシー(Same-Origin Policy)」とは
>Webブラウザから送信されるリクエスト（HTMLや画像など）を取得するためのリクエストした際に、リクエストが怪しくないかチェックするための仕組みが「同一生成元ポリシー(Same-Origin Policy)」。異なるオリジンからのリソースへのアクセスに制限をかけることができ、ページを開いたときに関連するリソースを同じオリジンからしか取得しない様にする。

参考：https://qiita.com/mtoyopet/items/326ba62d485e9ef0dacd



さっそく、Gemfileのコメントアウトを外してインストール。

```
gem 'rack-cors'
```
```
bundle install
```

```config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    # origins 'example.com'の部分をorigins '*'に変更
    # '*' ですべてのHTTPリクエストを許可する
    origins '*'

    resource '*',
      headers: :any,

      # exposeの行を追加することで、ブラウザからアクセスできるヘッダー情報を指定
      expose: ['access-token', 'expiry', 'token-type', 'uid', 'client'],
      # どのHTTPリクエストメソッドを許可するか指定
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end
```

# ルーティング

authディレクトリ内にあるregistrationsコントローラを使用し、
サインアップとログインを行うように設定。

```routes.rb
    Rails.application.routes.draw do
      mount_devise_token_auth_for 'User', at: 'auth', controllers: {
        registrations: 'auth/registrations'
      }
    end
```

# コントローラー

```
bundle exec rails g controller auth/registrations
```
```
ルートディレクトリ
└── app
    └── controllers
        └── auth
            └── registrations_controller.rb
```

```controllers/auth/registrations_controller.rb
#　DeviseTokenAuth::RegistrationsControllerから継承させる。
class Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController

    private

    def sign_up_params
      params.permit(:name, :email, :password, :password_confirmation)
    end
end
```

ざっくり設定はこれで終了です。
次回は、Postmanを使ってAPIの動作確認をしたいと思います。