LoginSignup
72
65

More than 5 years have passed since last update.

RubyでFirebaseを利用して認証を行う

Last updated at Posted at 2018-06-03

Rubyで Firebase で認証を行う実装のサンプルが見当たらなかったので業務で実装したものをまとめてみました。RubyでのFirebaseの活用例が増えれば幸いです。

Firebaseでの認証

Firebase Auth REST API を利用してユーザー登録、認証、セッショントークンの管理を行います。
Firebaseの uid からJWTを生成し、クライアントとの認証はJWTを介して行います。
Firebase Auth REST API のラッパーとして firebase-auth が便利だったので利用しています。

なお、Firebaseを利用した認証はセッションレスで常にJWTを介してリクエストを処理します。
トークンの有効期限が切れる毎に認証操作が発生するのを防ぐためにはクライアント側で発行されたJWTを保持する必要があります。

Firebaseのセッショントークンの有効期限は1時間です。
有効期限を過ぎたらリフレッシュトークンで新たにセッショントークンを生成する必要があります。

注意事項

Firebase Auth REST API は個人用(ログインユーザー)のAPIしか提供されていません。
例えば一部の不正行為をしたユーザーを利用停止するなどの操作がAPIでは実現できません(Firebaseコンソールからは可能)。
公式のSDK が提供されているNode.jsやGoといった言語は管理者用の操作も実行できます。
組織やグループ管理を扱うアプリケーションではFirebaseだけではユーザー管理に支障がでるので独自のユーザー管理の仕組を導入する必要があります。

サンプルアプリケーションの説明

firebase-auth-api をGitHubで公開しているので参考にしてください。
RailsのAPIサーバーになります。

実装の特徴

ユーザー管理をアプリケーションで行えるようにするためにFirebaseのuidを直接利用するのではなく users テーブルを導入しています。
users.deleted = true のユーザーはアカウントが無効となり、認証に失敗します。
トークンの更新時には必ずFirebaseでの認証と users.deleted の確認を行い無効になったユーザーがアプリケーションを不正操作し続けるのを防いでいます。
なお、JWTは独自に生成しているので有効期限を設定しないことも可能ですが、セキュリティ上の大きなリスクを生じることになるのでFirebaseに合わせて有効期限を1時間にしています。

Firebase::AuthClient がFirebaseへのリクエストを司どっています。
Firebase::AuthClient ラッパークラスで実際にリクエストを発行しているのは firebase-auth になります。
以下はメールアドレス・パスワードでの認証処理の実装の抜粋です。

module Firebase
  class AuthResponse
    attr_accessor :uid, :id_token, :refresh_token

    def initialize(raw_response)
      @uid = raw_response.body['localId'] || raw_response.body['user_id']
      @id_token = raw_response.body['idToken'] || raw_response.body['id_token']
      @refresh_token = raw_response.body['refreshToken'] || raw_response.body['refresh_token']
    end
  end

  class AuthenticationException < StandardError; end

  class AuthClient
    def self.client
      Firebase::Auth::Client.new(FIREBASE::API_KEY)
    end

    def self.sign_in_email!(email, password)
      response = client.sign_in_email(email, password)
      unless response.success?
        message = ERROR_MESSAGES[response.body['error']['message']] || 'ログインに失敗しました'
        raise Firebase::AuthenticationException.new(message)
      end

      Firebase::AuthResponse.new(response)
    end
  end
end

動作環境・バージョン

Ruby: 2.5.1
Rails: 5.2.0

セットアップ

bundle install 実行後に users テーブルを作成します。
なお、DBはPostgreSQLを前提にした実装になっているので他のDBを利用する場合は config/initializers/constants.rb の定数を書き換えてください。

bundle install
bin/rake db:migrate

Firebase

Firebaseプロジェクトで ログイン方法メール / パスワード を有効にしてユーザーを事前に登録してください。

firebase-authentication.png

環境変数

以下の設定を環境変数で指定します。

キー 値の例 説明
JWT_ALGORITHMS_TYPE HS256 JWTの署名アルゴリズム
JWT_EXPIRATIONTIME 3600 セッショントークンの有効期間(秒)
JWT_ACTIVITY_API_SECRET_KEY dummy 任意の文字列
FIREBASE_API_KEY AIz... FirebaseプロジェクトのAPIキー

API

以下のAPIを用意しています。
ユーザーの登録から、メールアドレス・パスワードでの認証、ユーザーの無効化が行えます。

URI メソッド パラメーター 説明
/session POST メールアドレス、パスワード 認証、セッショントークンの生成
/session PUT - セッショントークンのリフレッシュ
/user POST メールアドレス、パスワード、ユーザー名 ユーザーの登録
/user/:id DELETE - ユーザーの無効化
/user/current GET - ログインユーザーの情報を取得

クライアントからのHTTPリクエストには以下の形式のHTTPヘッダーを付加してください。
JWT にはセッショントークンをセットします。
トークンのリフレッシュ処理(PUT /session)を呼び出す場合だけリフレッシュトークンをセットします。

Authorization: Bearer eyJ...(JWT)

POST /user でもセッショントークンを要求しているのは組織やグループで利用する想定だからです。
その場合にユーザー登録をするのはグループのリーダーや組織の管理者となります。
一般ユーザー向けのアプリケーションなら POST /user は認証無しで実行できるようにしてください。

curlでのコマンド例

動作検証のためのcurlコマンドのサンプルです。
最初に POST /session で認証し、セッショントークン・リフレッシュトークンを取得してください。
他のAPIはセッショントークン、またはリフレッシュトークンが必要になります。

認証

curl -i -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"email": "user01@example.com","password": "dummy1234"}' http://localhost:3000/session
ユーザー登録

Authorization ヘッダーにはセッショントークンを設定します。

curl -i -H "Accept: application/json" -H "Content-type: application/json" -H "Authorization: Bearer eyJ..." -X POST -d '{"email": "user01@example.com","password": "dummy1234", "name":"user01"}' http://localhost:3000/user
ログインユーザーの情報取得

URIが /user/:id でない点に注意です。
ユーザーを特定するためのidはセッショントークンから取得するのが基本になります。

curl -i -H "Accept: application/json" -H "Content-type: application/json" -H "Authorization: Bearer eyJ..." http://localhost:3000/user/current
セッショントークンのリフレッシュ

Authorization ヘッダーにはリフレッシュトークンを設定します。

curl -i -H "Accept: application/json" -H "Content-type: application/json" -X PUT -H "Authorization: Bearer AK2..." http://localhost:3000/session
72
65
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
72
65