読者です 読者をやめる 読者になる 読者になる

生涯未熟

プログラミングをちょこちょこと。

Firebaseの2.x系から3.x系への対応

FirebaseのJSライブラリを2.x系から3.x系へ対応するための手順を書いてきます。

対応しなくちゃいけないところ

メジャーアップデートで認証の部分が大きく変わっています。 今までとは違い、Googleのサービスに依るところが入ってくるので少し厄介です。

対応の前フリ

2.x系と3.x系での相違点は以下の3つです。(他にもあるかも)

firebaseのinitialize

2.x系だと以下のような形でしたが、

new Firebase("http://hoge.firebaseio.com/");

3.x系では更にinitialize時にパラメータを渡す形に変更されました。

カスタムトークンの生成

2.x系だとカスタムトークンの生成は以下の様な感じでした。

payload = { uid: uid }
generator = Firebase::FirebaseTokenGenerator.new(firebase_secret)
generator.create_token(payload)

Gemのfirebase-token-generator-rubyを使い、カスタムトークンを生成しています。

しかし、今回3.x系のアップデートに伴い、このGemが使えなくなってしまいました。 (経緯:https://github.com/firebase/firebase-token-generator-ruby/issues/7

「んじゃどうすればいいの?」って感じになるかと思いますが、↑のISSUE内で言われているようにruby-jwtを使って作成しましょう。

カスタムトークンの認証

以前は authWithCustomToken を使った認証でしたが、こちらも変更になりました。

対応方法

firebaseのinitialize

initialize時にパラメータを引き渡してinitializeする必要がありますが、Firebaseのコンソール画面から一連のコードをコピーすることが出来ます!

まずはFirebaseのコンソールから プロジェクトの設定 をクリックします。

f:id:syossan:20160622230944p:plain

そして、設定の 全般 タグをクリックすると下の方に WebアプリにFirebaseを追加 とありますので、そこをクリックします。

f:id:syossan:20160622230959p:plain

すると、initializeのコードが表示されますので、 Initialize Firebase の部分のコードを使えばオーケーです!

f:id:syossan:20160622231010p:plain

カスタムトークンの生成

まずは ruby-jwtbundle install します。 そして、カスタムトークンの生成はマニュアルに従います。 https://firebase.google.com/docs/auth/server#use_a_jwt_library

$service_account_email = 'service-account@my-project-abc123.iam.gserviceaccount.com'
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, 'RS256'
end

自分の場合、ちょっとこのコードが気持ち悪かったので以下のようにしました。

  def generate_firebase_token
    service_account_email =  'service-account@my-project-abc123.iam.gserviceaccount.com'
    private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

    now_seconds = Time.now.to_i
    payload = {
      :iss => service_account_email,
      :sub => service_account_email,
      :aud => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
      :iat => now_seconds,
      :exp => now_seconds + ( 60 * 60 ), # Maximum expiration time is one hour
      :uid => uid,
      :claims => {:premium_account => false}
    }
    JWT.encode payload, private_key, 'RS256'
end

さて、ここで「service_account_emailとprivate_keyには何を設定すればいいのか?」という問題になります。 ここからがGoogle様の領分になります。

まずは、Google API Consoleへ行きます。

そこで、右上のプロジェクトがFirebaseのプロジェクトになっていることを確認してから、左部メニューの 認証情報 へ飛びます。

f:id:syossan:20160622231030p:plain

次に、 認証情報を作成 から サービスアカウントキー を選択します。

f:id:syossan:20160622231040p:plain

サービスアカウント は新しく分かりやすい名前で作成し、JSON形式を選択して作成します。

そうすると、認証情報が詰まったJSONがダウンロードできますのでそれを保存します。

認証情報は拾ってこれましたので、ここからはコードに反映する作業を行います。

先ほどのJSONにある認証情報をそのままコードに貼り付けてもいいのですが、セキュリティ的にマズイのでJSONを読み取ってから値を取得する方法を取ります。

    # JSONファイルの場所を指定
    auth_file = File.join(Rails.root, 'config', 'auth', 'development', 'auth.json')
    auth_data = open(auth_file) do |data|
      JSON.load(data)
    end

    # JSONの情報を設定
    service_account_email = auth_data['client_email']
    private_key = OpenSSL::PKey::RSA.new auth_data['private_key']

    now_seconds = Time.now.to_i
    payload = {
      :iss => service_account_email,
      :sub => service_account_email,
      :aud => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
      :iat => now_seconds,
      :exp => now_seconds + ( 60 * 60 ), # Maximum expiration time is one hour
      :uid => uid,
      :claims => {:premium_account => false}
    }
    JWT.encode payload, private_key, 'RS256'

これでカスタムトークンの生成は完了しました!

カスタムトークンの認証

authWithCustomToken から auth().signInWithCustomToken へ切り替えます。

firebase.auth().signInWithCustomToken(firebase_token).catch(function(error) {
    console.log(error)
});

これだけでオーケーです!