前回の記事でNuxt とFirebaseを使用したユーザー認証ができたので、今回の記事ではRailsの方でもユーザーの認証を行っていきます。
前回の記事はこちら: Nuxt + Rails + Firebase ユーザー登録 (Nuxt編)
今回使用するgemはfirebase-auth-railsです。
https://github.com/penguinwokrs/firebase-auth-rails
このgemを使用するとことでfirebaseと通信を行うことができ認証情報を取得できるのdeviseで使用していたcurrent_userのヘルパーメソッドを使用できます。
またこのgemは内部でfirebase_id_tokenというgemを使用していてそのgemではRedisを使っているのでそのセットアップ方法も記述しています。
早速、gemのREADMEに沿って進めていきます。
Railsセットアップ
1. gemのインストール
api/Gemfile
gem 'firebase-auth-rails' # 追記
Gemfileに記述できたらインストールします。
bundle install
2. ユーザーモデルの作成
続いてユーザーモデルを作成します。
api $ rails g model user
ファイルが作成できたらマイグレーションファイルを修正します。
api/db/migrate/xxxx_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :uid, null: false
t.timestamps
end
end
end
修正を反映させます。
api $ rails db migrate
3. initializers設定
initializerの設定を行っていきます。api/config/initializersディレクトリ下に firebase_auth_initializer.rbのファイルを追加してください。
api/config/initializers/firebase_auth_initializer.rb
FirebaseIdToken.configure do |config|
config.redis = Redis.new
config.project_ids = ['firebase_project_id']
end
ここのfirebase_project_idは自分のproject_idが入ります。
project_idは firebaseコンソール -> プロジェクトの概要の横にある歯車マー ク-> プロジェクトを設定 から確認できます。

4. モジュールインクルード
configの設定が完了したらモジュールをインクルードします。
api/app/controllers/application_controller.rb
class ApplicationController < ActionController::API
include Firebase::Auth::Authenticable
end
application_controlerにモジュールをインクルードしたのでこのコントローラを継承してるコントローラでAuthenticableのモジュールが使用できます。。
ユーザーがログインしているかチェックしたいところに before_action :authenticate_user を記述すればdeviseと同じようにユーザーのチェックと current_user を取得できます。
5. ユーザー登録処理
続いてユーザーの登録処理を実装していきます。
ルーティング
api/config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
namespace 'users' do
resources :registrations, only: [:create]
end
## 省略
コントローラ
api/app/controllers/api/v1/users/registrations_controller.rb
module Api
module V1
module Users
class RegistrationsController < ApplicationController
def create
raise ArgumentError, 'BadRequest Parameter' if payload.blank?
user = User.create!(sign_up_params.merge(uid: payload['sub']))
render json: user, status: :ok
end
private
def sign_up_params
params.require(:registration).permit(:email)
end
def token_from_request_headers
request.headers['Authorization']&.split&.last
end
def token
params[:token] || token_from_request_headers
end
def payload
@payload ||= FirebaseIdToken::Signature.verify token
end
end
end
end
end
簡単にコードの説明をすると /api/v1/users/registrations のPOSTリクエストの際にトークンをチェックしてトークンが正しければユーザーを作成し、トークンが正しくなかったらエラーを返す処理を行っています。
ひとまずRails側のfirebaseのトークン認証からユーザー作成までの実装は完了しました。
Nuxt 登録処理修正
Rails側のユーザー登録処理が実装できたのでNuxt側で新規登録した際に /api/v1/users/registrations のPOSTリクエストを送信するよう記述を修正していきます。
methods: {
signup() {
firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
.then((res) => {
const params = { token: res.user.za, registration: { email: res.user.email } }
const url = '/api/v1/users/registrations'
this.$axios.post(url, params)
.then((res) => {
console.log(res)
this.$router.push('/')
})
.catch((error) => {
// TODO: ユーザー作成に失敗した場合の処理追加
console.log(error)
})
})
createUserWithEmailAndPassword() の処理に成功したレスポンスの中のuserの中のzaというキーがトークンにあたるのでそれとメールアドレスをパラメータとしてrails側に送ります。
Nuxt側もこれで実装が完了したので実際に新規登録してみるのですが、下記のようなエラーが返ってきました。
Redis::CannotConnectError (Error connecting to Redis on 127.0.0.1:6379 (Errno::ECONNREFUSED)):
調べてみると以下のようなことがわかりました。
内部でfirebase_id_tokenというgemを使っていて、このgemはRedisが必須のためインストールしておきます。 google x509 証明書とその期限を管理するためにRedisを使っているようです。
https://simple-minds-think-alike.hatenablog.com/entry/rails-firebase-authentication
Redisの設定がまだなのでエラーが返ってきたみたいです。なのでRedisの設定を行っていきます。
Redis設定
homebrew で redis をインストールします。
api $ brew install redis
redis がインストールされているかは下記コマンドで確認できます。
$ which redis-server
/usr/local/bin/redis-server <= インストールできている場合このように表示されます。
redis を起動します。
api $ redis-server
FirebaseIdToken のトークン確認をするにはリクエストが必要なのでコンソールからリクエストを送信します。
api $ rails c
> FirebaseIdToken::Certificates.request
> FirebaseIdToken::Certificates.present?
=> true
FirebaseIdToken::Certificates.present?でtrueが返ってきたらトークン確認が行えるようになっています。
もう一度ユーザー登録を行います。
下記画像のようにレスポンスが返ってきたら成功です。

以上で「Nuxt側でユーザー新規登録をした時にRails側でもユーザーを追加」の実装は完了です。
図にすると以下のような順序で登録処理が行われています。

Nuxt Headers情報追加
最後にcurrent_user情報を取得するためにリクエストのヘッダー情報にトークンを追加します。
ドキュメントには以下のように記述して追加できると書いています。
// Adds header: `Authorization: Bearer 123` to all requests
this.$axios.setToken('123', 'Bearer')
authentication.jsのplugins内でユーザーの情報が取得できたらヘッダーにトークン情報をセットします。
front/plugins/authentication.js
import firebase from '~/plugins/firebase'
export default function ({ $axios, route, redirect, store }) {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
store.commit('user/login')
const token = user.za
$axios.setToken(token, 'Bearer')
} else {
// No user is signed in.
if (route.path !== '/login') {
redirect('/login')
}
}
});
}
storeの中身はこのようになっています。
front/store/user.js
export const state = () => ({
loggedIn: false,
})
export const mutations = {
login(state) {
state.loggedIn = true
},
}
これでユーザー認証されていたら全てのリクエストのヘッダーにこのトークン情報が付与されるのでこのトークン情報をRails側で受け取ってfirebaseと認証してcurrent_userを取得できるようになりました。
しかし今のまま /posts にアクセスするとNuxtのfirebase認証より postsのGETリクエストの方が早く実行されるRails側ではトークン情報がない状態になってしまいます。
なのでstoreでログイン状況を管理してログインが確認できたタイミングでGETリクエストを送るように修正します。
front/pages/posts/index.vue
export default {
computed: {
loggedIn() {
return this.$store.state.user.loggedIn
},
},
methods: {
fetchContents() {
console.log('posts')
const url = "/api/v1/posts"
this.$axios.get(url)
.then((res) => {
this.posts = res.data.posts
})
},
},
watch: {
loggedIn: function() {
if (this.loggedIn) {
this.fetchContents()
}
}
},
}
これでユーザーの認証が完了してから/api/v1/postsのGETリクエストが実行されるようになったのでRails側でcurrent_userが取得できるか確認してみます。
indexアクションにbinding.pryを追加します。
api/app/controllers/api/v1/posts_controller.rb
module Api
module V1
class PostsController < ApplicationController
before_action :authenticate_user
def index
binding.pry
@posts = Post.all.order(updated_at: :desc)
end
追加できたらhttp://localhost:8080/posts にアクセスしてコンソールの方を止めてでcurrent_userと入力します。

current_userが取得できました。
以上でNuxt + Rails + Firebaseのユーザー認証の実装は終了です。
最後までご覧いただきありがとうございました。