💎

Rails 6.0 + Docker + MySQL5x + devise-token-auth での環境構築

2021/11/28に公開

この記事の概要

  • RailsのAPIモードで認証周り作ったときに苦労したので、備忘録メモとして…。

成果物


各種バージョン

  • Ruby 2.7
  • Rails 6.0.0
  • mysql 5.7.21

前提条件

  • Dockerを使える環境が整っていること

できること

  • Rails 6.0 + Docker + MySQL5x + devise-token-auth での環境構築
  • devise-token-authを使った、サインアップ、サインイン、サインアウトができる
  • ユーザがサインインしていることを確認し、サインインしていたらuser情報を取得する

できないこと(やらないこと)

  • コピペで環境構築できるように作った記事なので、各項目の詳しい説明は割愛

環境構築手順

1. try-rails6-api のテンプレートを使用し、リポジトリを作成する

  • リポジトリ名は try-rails6-api-with-devise とする
  • 必要に応じて、 try-rails6-api と記載している箇所を自分で作成したリポジトリ名に変更する(当記事であれば try-rails6-api-with-devise に変更)

2. try-rails6-apiのREADME.md に沿って環境構築する

3. 必要なGemを追加する

Gemfile

Gemfile
・
・
・

# 認証
gem "devise"
gem "devise_token_auth"

# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
# ※ 疎通確認をPostmanでする場合、必要となる場合があるので追加しておく
gem 'rack-cors' 

4. ビルド&追加したGemをインストールする

docker-compose build --no-cache
docker-compose run back bundle exec rails g devise:install
docker-compose run back bundle exec rails g devise_token_auth:install User auth

5. devise_token_auth の設定

config/initializers/devise_token_auth.rb

config/initializers/devise_token_auth.rb
# frozen_string_literal: true

DeviseTokenAuth.setup do |config|
  # By default the authorization headers will change after each request. The
  # client is responsible for keeping track of the changing tokens. Change
  # this to false to prevent the Authorization header from changing after
  # each request.
  config.change_headers_on_each_request = false

  # By default, users will need to re-authenticate after 2 weeks. This setting
  # determines how long tokens will remain valid after they are issued.
  # config.token_lifespan = 2.weeks

  # Limiting the token_cost to just 4 in testing will increase the performance of
  # your test suite dramatically. The possible cost value is within range from 4
  # to 31. It is recommended to not use a value more than 10 in other environments.
  config.token_cost = Rails.env.test? ? 4 : 10

  # Sets the max number of concurrent devices per user, which is 10 by default.
  # After this limit is reached, the oldest tokens will be removed.
  # config.max_number_of_devices = 10

  # Sometimes it's necessary to make several requests to the API at the same
  # time. In this case, each request in the batch will need to share the same
  # auth token. This setting determines how far apart the requests can be while
  # still using the same auth token.
  # config.batch_request_buffer_throttle = 5.seconds

  # This route will be the prefix for all oauth2 redirect callbacks. For
  # example, using the default '/omniauth', the github oauth2 provider will
  # redirect successful authentications to '/omniauth/github/callback'
  # config.omniauth_prefix = "/omniauth"

  # By default sending current password is not needed for the password update.
  # Uncomment to enforce current_password param to be checked before all
  # attribute updates. Set it to :password if you want it to be checked only if
  # password is updated.
  # config.check_current_password_before_update = :attributes

  # By default we will use callbacks for single omniauth.
  # It depends on fields like email, provider and uid.
  # config.default_callbacks = true

  # Makes it possible to change the headers names
  config.headers_names = {:'access-token' => 'access-token',
                         :'client' => 'client',
                         :'expiry' => 'expiry',
                         :'uid' => 'uid',
                         :'token-type' => 'token-type' }

  # By default, only Bearer Token authentication is implemented out of the box.
  # If, however, you wish to integrate with legacy Devise authentication, you can
  # do so by enabling this flag. NOTE: This feature is highly experimental!
  # config.enable_standard_devise_support = false

  # By default DeviseTokenAuth will not send confirmation email, even when including
  # devise confirmable module. If you want to use devise confirmable module and
  # send email, set it to true. (This is a setting for compatibility)
  # config.send_confirmation_email = true
end

6. rack-cors の設定

rack-cors がインストールされていることを確認する

docker-compose run --rm back bundle info rack-cors

設定ファイル作成

touch config/initializers/core.rb

config/initializers/core.rb

config/initializers/core.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "localhost:3000" # フロント側のポート番号を指定

    resource "*",
      headers: :any,
      expose: ["access-token", "expiry", "token-type", "uid", "client"],
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

7. Modelの設定

app/models/user.rb

app/models/user.rb
# frozen_string_literal: true

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
          :rememberable, :validatable
  include DeviseTokenAuth::Concerns::User
end

8. Controllerの設定

(01) Registrations Controller

コントローラ作成
docker-compose run back rails g controller v1/registrations --no-assets --no-helper
app/controllers/v1/registrations_controller.rb
app/controllers/v1/registrations_controller.rb
module V1
  class RegistrationsController < DeviseTokenAuth::RegistrationsController
    private
      def sign_up_params
        params.permit(:email, :password, :password_confirmation, :name)
      end
  end
end

(02) Users Controller

コントローラ作成
docker-compose run back rails g controller v1/users --no-assets --no-helper
app/controllers/v1/users_controller.rb
app/controllers/v1/users_controller.rb
module V1
  class UsersController < ApplicationController
    
    # Sign inしてないと以下のMethodは実行できない
    before_action :authenticate_v1_user!
    
    # 全件検索
    def index
      user = User.all
      if user
        render json: { user: user}, status: :ok
      else
        render user
      end
    end

  end
end

(03) Application Controller

app/controllers/application_controller.rb
app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  include DeviseTokenAuth::Concerns::SetUserByToken
  rescue_from ActiveRecord::RecordNotFound, with: :render_404
  before_action :configure_permitted_parameters, if: :devise_controller?
    
  def render_404
    render status: 404, json: { message: "record not found." }
  end

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end

9. Routingの設定

config/routes.rb

config/routes.rb
Rails.application.routes.draw do
  mount_devise_token_auth_for 'User', at: 'auth'
  namespace :v1, defaults: { format: :json } do
    get :healthcheck, to: 'sessions#healthcheck'
    mount_devise_token_auth_for 'User', at: 'auth', controllers: {
      registrations: 'v1/registrations',
      sessions: "devise_token_auth/sessions"
    }
    resources :users
  end
end

10. マイグレーション実行

docker-compose run --rm back  bundle exec rake db:migrate

疎通確認

  • Postmanを使用

1. コンテナ起動

docker-compose up

2. サインアップ

URL

[POST] http://localhost:4000/v1/auth

Body: raw(JSON)

{"email": "sample@test.com", "password": "xxxxxxxx", "name": "サンプル 太郎"}

3. サインイン

URL

[POST] http://localhost:4000/v1/auth/sign_in

Body: raw(JSON)

{"email": "sample@test.com", "password": "xxxxxxxx"}

4. サインアウト

URL

[DELETE] http://localhost:4000/v1/auth/sign_out

Headers

  • サインインで取得した、以下の項目を設定する
    • access-token
    • uid
    • client
    • expiry
    • content-type
    • token-type

5. ユーザ情報取得(サインインしていないと取得できない)

URL

[GET] http://localhost:4000/v1/users

Headers

  • サインインで取得した、以下の項目を設定する
    • access-token
    • uid
    • client
    • expiry
    • content-type
    • token-type

Discussion