Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
45
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@asflash8

RubyでだってFirebase Admin SDKは作れる!!

はじめに

この記事は、Hamee Advent Calendar 2019の15日目のエントリです。
最近はRailsの傍らTerraformをごにょごにょしています。Terraformなんもわからん。

最初に結論

タイトルは言い過ぎました。正確には
RubyでもFirebase AuthenticationからAdmin SDKのようにユーザーの取得や更新はできる!!
(最後にUserManagementの一部機能のサンプルコードあり)

※今回は一部機能しか実装していませんが、がんばればAdmin SDKは作れます。

Ruby+Firebase使ってます

みなさんFirebase使ってますか?

私はここ一年くらいで初めて、とあるプロジェクトでFirebaseを使ってみて、いまさらながらあまりの便利さと機能の豊富さに震えました。認証もプッシュ通知もFaaSもデータベースもなんでもあるやん・・・すごい(語彙力):open_mouth:

こんなすばらしいプロダクトを利用できることに感謝しながら、Railsなサーバーと連携する形でFirebaseを使っていたんですが、あるとき機能改修でuidを使ってRubyからFirebase Authenticationにいるユーザー情報を取得したいケースがでてきました。

Gemがない

さて実装しようと思ったら、ないんですよ。Firebase公式のAdminSDKにRuby実装が。まあ、Rubyのエコシステムなら3rd PartyのGemくらいあるやろーと思って探してみたところ、あれ・・・ない?

firebase-rubyというGemはあるんですが、Firebase Database REST APIのラッパーになっていて、Authenticationへのアクセス機能は持っていない。firebase-authといういかにもな名前のGemも、idToken(Firebaseの認証トークン)を使えばユーザー情報の取得はできるのですが、uidを使ってユーザー情報が取得できないので今回のやりたいことに合わず断念。

諦めかけていたそのとき・・・

不本意だけど、あまり時間もかけていられないし公式のAdminSDKがあるnodeを間に立てて、Rails -> node -> Firebaseという構成でアクセスする実装を進めていました。

ちょうどアドカレネタを探していたところだったのもあって、諦めきれずに調べていたら、How to access account info of firebase auth?といういかにもそれっぽいissueを発見。issue内で取得できたよーって書いてあるじゃないですか!!!

結果、google-api-clientを使えばRubyからでもAdminSDK相当のことができそうなことがわかり、実際に試してみたところ無事にuidでユーザーが取得できました。プロジェクトにもフィードバックして無駄にnodeを経由することを回避できたのでした。

:muscle::muscle::muscle::muscle::muscle:アドカレ駆動開発:muscle::muscle::muscle::muscle::muscle:

前置きが長くなりましたが、以下手順とサンプルコードです。

前準備

  1. サーバーに Firebase Admin SDK を追加するを参考に、サービスアカウント用の秘密鍵ファイルを生成・ダウンロードしておく
  2. google-api-client Gemをインストールしておく

サンプルコード

require 'google/apis/identitytoolkit_v3'

# 前準備の1で用意したjsonファイルのパス
service_account_key_json = "/path/to/your/serviceAccountKey.json"

# Googleの認証用サービスの初期化
service = Google::Apis::IdentitytoolkitV3::IdentityToolkitService.new

# 認証用クレデンシャルの生成
service.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open(service_account_key_json),
  scope: [
    # 認可が必要なスコープを列挙する。今回はidentitytoolkitのみ
    # ここにFirebaseの各種サービスを指定することでUserManagement以外も利用可能
    'https://www.googleapis.com/auth/identitytoolkit',
  ].join(' ')
)

# 取得したいFirebaseのUIDを定義(予めFirebaseUIDはRuby側で取得してある想定)
uid = 'target firebase uid'

# 認証サービスへのリクエストの生成(uidでのユーザー情報の取得)
# ※引数が配列な点に注意(複数uidを渡せるが今回は1つとしている)
request = Google::Apis::IdentitytoolkitV3::GetAccountInfoRequest.new(local_id: [uid])

# リクエスト実行
account = service.get_account_info(request)

# ユーザーの取得
firebase_user = account.users[0]

# メールアドレス
firebase_user.email

FirebaseのGemで探していたから見つからなかっただけで、FirebaseもGoogleのサービスの一つなんだからGoogleのGemという切り口で探してみたところたどり着けたのでした。視点の切り替え大事。

あと、諦めなくてよかった:raised_hands:

ちなみに更新もできます

uid以外にも電話番号やメールアドレスでのユーザー取得や更新もできます。

Gemfile
# frozen_string_literal: true
source 'https://rubygems.org'
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'google-api-client'
firebase_admin/auth/client.rb
require 'google/apis/identitytoolkit_v3'

module FirebaseAdmin
  module Auth
    class Client
      def initialize(service_account_key_json_path)
        @service = Google::Apis::IdentitytoolkitV3::IdentityToolkitService.new
        @service.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
          json_key_io: File.open(service_account_key_json_path),
          scope: [
            'https://www.googleapis.com/auth/identitytoolkit',
          ].join(' ')
        )
      end

      def get_user(uid:)
        get_account_info(local_id: [uid])&.users&.first
      end

      def update_user(uid:, params:)
        update_params = { local_id: uid }.merge(params)
        request = Google::Apis::IdentitytoolkitV3::SetAccountInfoRequest.new(update_params)
        @service.set_account_info(request)
      end

      def get_account_info(params)
        request = Google::Apis::IdentitytoolkitV3::GetAccountInfoRequest.new(params)
        @service.get_account_info(request)
      end
    end
  end
end

こんなファイルを用意しておいて

require_relative 'firebase_admin/auth/client'
service_account_key_json_path = '/path/to/serviceAccountKey.json'

client = FirebaseAdmin::Auth::Client.new(service_account_key_json_path)

# メールアドレスでの検索
account = client.get_account_info(email: [検索したいメールアドレス])
# 電話番号での検索
account = client.get_account_info(phone_number: [検索したい電話番号])

# メールアドレスの更新
uid = '更新対象のUID'
client.update_user(uid: uid, params: { email: 'update.email@example.com' })

とすればUID以外での検索や更新なども可能です。

Firebase Authenticationに認証は任せているが、Railsからメールは送りたいといった場合でも問題なく実現できます。Rubyだからって諦めなくていいんです。

まとめ

素直に公式のAdminSDK実装がある言語でFirebaseを使おう
RubyからでもFirebaseAdminSDK相当の機能は実現できる:tada:

今回紹介したのはUserManagementの一部だけでしたが、scopeの指定をすれば他の機能も実現できそうなので、時間を見つけて実装してみようと思います。

参考リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
45
Help us understand the problem. What are the problem?