devise_token_authでvue3+railsアプリのユーザー認証登録の実装をする。

rails

railsでは、ユーザー認証機能としてdeviseがありますが、今回はトークンによる認証ができるdevise_token_authの設定方法について紹介します。

本記事では、devise_token_authとは何かやvue3+railsでdevise_token_authを用いたユーザーの登録の実装方法について説明しています。

今回構築した環境

  • vue: 3.3.4
  • rails: 6.1.7.3
  • devise_token_auth: 1.2.2
  • docker-composeを使用したdocker環境

devise_token_authって何?

devise_token_authとは、トークン方式の認証機能になります。

deviseとの違いは、トークンを渡すか渡さないかになります。

devise_token_authはどういう時に必要かというと、railsをAPIモードで使用して、フロントをVueやReactなど別で持つ場合です。ruby on railsで実装する場合は、rubyとrailsが同じアプリケーションサーバーで動いているため、rubyとrailsが連携されていますが、APIモードの場合、アプリケーションが別々のため、railsが認証していても、フロント側は認証しているかがわかりません。

そこで、rails側からブラウザへトークンを渡すことで、front側はログイン状態を認識することができると言うことです。

それでは実装方法について説明していきます。

バックエンド(rails)側でdevise_token_authの環境を構築する

devise_token_authをrailsに導入する

railsのgemfileに下記を追加します。

gem 'devise_token_auth'
gem 'devise'
gem 'rack-cors'
bundle install

bundle installでdevise、devise_token_auth、corsをインストールしてください。

rails g devise:install
rails g devise_token_auth:install User auth # Userモデルにdevise機能がマウントされる

migrateファイルを編集・migrationを実行する

作成したuserは、基本情報としてname、nickname、image、emailカラムが用意されています。descriptionなど、他のカラムの設定が必要な場合はmigrationファイルに追記しましょう。

## User Info
    t.string :name
    t.string :nickname
    t.string :image
    t.string :email
    t.string :description # カラムを追加したい場合は記載

追加したらmigrationを実行します。

rails db:create # createしてない場合はまずcreate
rails db:migrate

corsを設定する

devise_token_authでは、cors(cross origin resource sharing)を設定する必要があります。

これを設定することで、クライアントサーバーとして使用するfrontendアプリ以外からrailsにアクセスするのを防ぎます。

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:8080' # ここは自身のフロントエンドアプリのホストを指定する
 # origins ENV['APP_HOST'] のように環境変数にしておくと本番環境に移行する時にスムーズです。

    resource '*',
      headers: :any,
      expose: ['access-token', 'expiry', 'token-type', 'uid', 'client'], #ここを追加する
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

ここで、最も重要なのは、exposeを設定することです。ここで、access-tokenやらuidやらをheaderに載せて、railsからフロントエンド側へレスポンスとして返すことができます。

また、本番環境でも反映させることを考えて、originsは環境変数にしておくと便利です。

ルーティングを作成する

routesにdevise用コントローラのルーティングを設定します。

Rails.application.routes.draw do

  ...
  mount_devise_token_auth_for 'User', at: 'auth', controllers: {
    registrations: "auth/registrations"
  }
  ...

end

おそらく、当初はmount_devise_token_auth_for ‘User’, at: ‘auth’ となっていたと思いますが、今回は、controllerにアレンジを加えたいのでcontrollersを指定します(デフォルトのままでいい場合は、ルーティングの変更は必要ありません)。

上記のようにすることで、controllers/auth/registrations_controller.rbにdevise_token_authのデフォルトのコントローラに上書きをすることができます。

本来はdeviseをインストールした時点でdeviseのコントローラを継承することができており、コントローラを作成する必要はありません。ソースコードはこちら↓

application_controllerを見てみると、deviseのコントローラをincludeしているため、controllerを新たに作成することなくdeviseを使用することができます。

controllerの作成(アレンジ)

class Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController
  private

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

上記のコードでは、ユーザー登録時のparamsを設定しています。デフォルトだと、email、password、password_confirmationだけなのですが、今回は名前の登録もしたいので、nameを追加しました。

このように、controllerをデフォルトのものからアレンジしたい場合は、controllerを作成してコードを上書きします。

フロントエンド(vue)側の環境構築

サインアップ画面を作成する

サインアップページを作成します。今回はviewsディレクトリ配下にあらたにauthディレクトリを作成し、その配下にSignupPage.vueを作成し、サインアップ画面を作成していきます。ルーティングとページの紐付けに関しては下記の記事で解説しています。

サインアップ時のコードを掲載します。

<script setup>
  import { ref } from 'vue'
  import axios from 'axios'
  import router from '../../router' # ←適宜変更してください

  const user = ref({
    name: '',
    email: '',
    password: '',
    password_confirmation: ''
  })
  const registerUser = async() => {
    axios.post('/auth', {user: user.value})
    .then((response) => {
      localStorage.setItem("access-token", response.headers["access-token"])
      localStorage.setItem("client", response.headers["client"])
      localStorage.setItem("uid", response.headers["uid"])
      router.push({ path: '/' }) # ←適宜変更してください
    })
    .catch((error) => {    
    console.log(error)    
  })
  }

</script>
<template>
<div class="signup-container">
  <h1>ユーザー登録</h1>
    <form @submit.prevent="registerUser" class="my-5">
      <div class="m-2 row">
        <label for="name" class="col-3">名前:</label>
        <input type="text" id="name" class="w-100 col-9" v-model="user.name" required>
      </div>
      <div class="m-2 row">
        <label for="email" class="col-3">メールアドレス:</label>
        <input type="email" id="email" class="w-100 col-9" v-model="user.email" required>
      </div>
      <div class="m-2 row">
        <label for="password" class="col-3">パスワード:</label>
        <input type="password" id="password" class="w-100 col-9" v-model="user.password" required>
      </div>
      <div class="m-2 row">
        <label for="password_confirmation" class="col-3">パスワード確認:</label>
        <input type="password" id="password_confirmation" class="w-100 col-9" v-model="user.password_confirmation" required>
      </div>
      <button type="submit" class="btn btn-outline-primary">登録</button>
    </form>
</div>
</template>
<style>
  .signup-container {
    max-width: 600px;
    margin: 0 auto;
  }
</style>

画面としてはこんな感じ

ユーザー登録フォームを作成し、登録が成功したら、

  • railsからVueにトークン情報などが送られる
  • VueからlocalStorage(ブラウザ)にトークン情報を保存する
  • 今後、フロントエンドからバックエンドに処理をリクエストする際は、ブラウザ側からheader情報を受け取り、rails側に渡すことで、どのユーザーからアクセスが来ているか分かる。

上記の流れが可能になり、ユーザーを判別できるようになります。

localStorage.setItem("access-token", response.headers["access-token"])
localStorage.setItem("client", response.headers["client"])
localStorage.setItem("uid", response.headers["uid"])

rails側ではrailsが持っているaccess-tokenと照合することで、このリクエストはどのユーザーからかを知ることができます。ログアウトするときはlocalStorageから上記情報をremoveします。

devise_token_authによるvue3の認証の実装まとめ

以上、devise_token_authを使用してサインアップする手順を解説しました!

signinやsignoutなどの実装も追々追加していく予定です!

コメント

タイトルとURLをコピーしました