今回はdevise_token_auth
を使っての認証機能について解説しようと思います。
devise_token_authとは?
トークンベースの認証を行いたい場合devise_token_authというGemを使います。
トークンベースの認証とは、ユーザー情報を確認し、代わりに一意のアクセストークンを受け取ることを可能にするプロトコルです。
トークンの存続期間中、ユーザーはトークンが発行されたWebサイトやアプリにアクセスできます。
同じトークンで保護されたWebページ/アプリ/リソースに再度アクセスするたびに、資格情報を再入力する必要はありません。
認証トークンが有効である限り、ユーザーはアクセスを保持します。ユーザーがログアウトすると認証トークンは無効になります。
Railsではdevise
をログインなどで使う場合もあると思います。
deviseはCookieベースの認証を行う場合に使用します。
devise_token_authを使えるようにする
ここでは、devise_token_authを使えるようにします。
今回はDBはあらかじめ作成している状態から進めたいと思いますのでご了承ください。
devise、devise_token_auth、rack-corsの3つを使うので、3つをGemfileに追加しましょう。 deviseを先にインストールしていないとエラーになることがあるので、先にdeviseをインストールしましょう。
gem 'rack-cors' gem 'devise' gem 'devise_token_auth'
bundle install
するとインポートできているはずです。
ただし、devise_token_authは次のコマンドでインストールしてください。
$ rails g devise_token_auth:install User auth
devise_token_auth.rbの設定
成功すると、config/initializers/devise_token_auth.rb
というファイルが作成されているはずです。
ファイルの中身を確認して次の変更を行なってください(場合に応じて)。
// コメントを外してtrueからfalseに変更する config.change_headers_on_each_request = false // コメントをはずす config.token_lifespan = 2.weeks // コメントを外す config.headers_names = {:'access-token' => 'access-token', :'client' => 'client', :'expiry' => 'expiry', :'uid' => 'uid', :'token-type' => 'token-type' }
config.change_headers_on_each_request
は trueの場合、リクエストごとにtokenを新しくする必要があるという設定になります。
毎回、トークンが変更されるという動きは今回は期待していないので、falseに変更します。
token_lifespan
はtokenの有効期間を定義します。今回は、2週間に設定しておきます。
headers_names
は認証用ヘッダーの名前の定義です。必要でない限り、変更しなくて良いと思います。
Userモデルの設定
devise_token_authの導入に成功していれば、db/migrate/日付_devise_token_auth_create_users.rb
というマイグレーションファイルが作成されていると思います。
デフォルトである程度定義されていますが、必要に応じてカラムを追加してください。
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[7.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 => "password" ## 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 :email ## Tokens t.json :tokens t.timestamps end add_index :users, [:email, :encrypted_password], 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
作成したら、マイグレーションを行います。
$ rails db:migrate
さらに、ユーザーモデルを修正していきます。
models/user.rb
というファイルがあるはずなので下記のように修正します。
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable include DeviseTokenAuth::Concerns::User end
deviseではモジュールの設定を定義して、使える機能を定義しています。 下記のような機能があるので、使用したいものを羅列していきます。
機能 | 概要 |
---|---|
database_authenticatable | パスワードを暗号化してDBに登録する機能 |
registerable | 登録処理を通してユーザーをサインアップする機能。ユーザーに自身のアカウントを編集したり削除することを許可します。 |
recoverable | パスワードをリセットし、通知する機能 |
rememberable | 保存されたcookieから、ユーザーを記憶するためのトークンを生成・削除する機能 |
trackable | サインイン回数や、サインイン時間、IPアドレスを記録します |
validatable | Emailやパスワードのバリデーションを提供します。独自に定義したバリデーションを追加することもできます |
confirmable | メールに記載されているURLをクリックして本登録を完了するという認証機能 |
lockable | 一定回数サインインを失敗するとアカウントをロックします。ロック解除にはメールによる解除か、一定時間経つと解除するといった方法があります |
timeoutable | 一定時間活動していないアカウントのセッションを破棄します |
omniauthable | TwitterやFacebookなどの認証機能 |
application_controller.rbの設定
app/controllers
配下にapplication_controller.rbが作成されていると思うので、次のように変更してください。
class ApplicationController < ActionController::Base // 追加 include DeviseTokenAuth::Concerns::SetUserByToken end
上記を追加することでSetUserByTokenという拡張機能を使えるようになります。
DeviseTokenAuth::Concerns::SetUserByToken
は、ユーザーのトークンを使用して認証された場合に、current_user
やuser_signed_in?
などのヘルパーメソッドを提供するためのコードが含まれたモジュールです。
このモジュールをApplicationControllerに含めることで、全てのコントローラーでこれらのヘルパーメソッドを使用できるようになります。
application_controller.rbの設定
config/application_controller.rb
ではexpose: ["access-token", "expiry", "token-type", "uid", "client"]
を設定して、フロントエンドでもトークンの情報を確認できるようにします。
config.middleware.insert_before 0, Rack::Cors do allow do origins ENV["API_DOMAIN"] resource '*', headers: :any, expose: ["access-token", "expiry", "token-type", "uid", "client"], methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
ルーティングの設定
ルーティングの設定のために、config/routes.rb
に変更を加えます。
Rails.application.routes.draw do // 追加 mount_devise_token_auth_for 'User', at: 'auth', controllers: { registrations: 'signup' } end
registrations: 'signup'
のsignupは適時変更してください。コントローラー名になります。
他の記事では、'auth/registrations'
となっていることが多いです。
会員登録とログイン
ここからは実際に会員登録やログインの処理を見ていこうと思います。
まず、ここまで実行していれば、ルーティングは行われているはずなので、確認してみましょう。
rake routes
を行うと次のように表示されるはずです。(表形式にしています)
Prefix Verb | URI Pattern | Controller#Action |
---|---|---|
new_user_session | GET /auth/sign_in(.:format) | devise_token_auth/sessions#new |
user_session | POST /auth/sign_in(.:format) | devise_token_auth/sessions#create |
new_user_registration | GET /auth/sign_up(.:format) | signup#new |
user_registration | POST /auth(.:format) | signup#create |
このように一部抜粋なのですが、ルーティングされているので、その情報をもとにして進めます。
Controllerの修正
まずは会員登録についてです。
会員登録はURIパターンがPOST /auth(.:format)
なのでSignUpControllerを作成する必要があります。
class SignupController < DeviseTokenAuth::RegistrationsController def sign_up_params params.permit(:email, :password, :password_confirmation) end end
上記のようにすることで、DeviseTokenAuthのRegistrationsControllerを継承しています。 そして、DeviseTokenAuth::RegistrationsControllerで定義されているsign_up_paramsの設定を更新しています。
フロントエンド(今回はVue.js)では次のように呼び出します。
async signUp () { try { const res = await axios.post(import.meta.env.VITE_APP_API_BASE + '/auth', { email: this.email, password: this.password, password_confirmation: this.passwordConfirmation }) console.log(response.headers["access-token"]) console.log(response.headers["client"]) console.log(response.headers["uid"]) } catch (error) { console.log({ error }) } }
成功すれば、responseの中にトークンの情報があるはずなので以降はトークンの情報をヘッダーに付与してリクエストを行います。
ログインはURIパターンがPOST /auth/sign_in(.:format)
なので、devise_token_auth/sessions#createを使用します。
ルーティングの際に、mount_devise_token_auth_forを使ってUserモデルに対してDevise Token Authをマウントしたので、devise_token_auth/sessions#createなどのデフォルトのアクションが自動的に使えます。
カスタマイズする場合には継承したクラスを作成するという流れになるのですが、IDとパスワードでログインするだけであれば特に継承する必要はないと思います。
フロントエンドでは次のように呼び出します。
async login() { try { const response = await axios.post(import.meta.env.VITE_APP_API_BASE + '/auth/sign_in', { email: this.email, password: this.password, }) console.log(response.headers["access-token"]) console.log(response.headers["client"]) console.log(response.headers["uid"]) } catch (error) { console.log({ error }) } }
大まかに解説しましたが、認証機能はどのアプリケーションでも使用すると思うので、ぜひ細かく調べてみてください!
参照
https://qiita.com/kskumgk63/items/aa581b6b3f8c66fa82e2qiita.com