252
213

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Firebase Auth のユーザ認証機能を自前のデータベースと連携する

Posted at

認証だけfirebase使いたい場合の考察。

要求

  • ユーザ認証(登録・ログイン)はfirebaseに任せたい。
  • ユーザデータはAWS RDS等別途のシステムで管理したい。

全体像

  1. Firebase <-> client ... ユーザ登録・ログイン(アクセストークンの発行)
  2. client -> self-backend ... アクセストークンの送信
  3. self-backend <-> Firebase ... アクセストークン検証、uid(firebase user ID)の確認
  4. self-backend -> client ... 認証可否含めたレスポンスの返却

詳細

1. Firebase <-> client ... ユーザ登録・ログイン(アクセストークンの発行)

  • firebaseとclient間のみのやりとりでユーザ認証をしアクセストークンを得る
  • ドキュメント通り実装する https://firebase.google.com/docs/auth/?hl=ja
  • 必要なプロバイダー(facebook, twitter, emailなど)毎の実装
  • ios/android/webどれでも対応可能

2. client -> self-backend ... アクセストークンの送信

  • 認証完了した際に得られるアクセストークンを自サービスのbackendに投げる
  • 自前backendにリクエストする際にAuthorization: Bearer {TOKEN}httpヘッダつけるのが素直な実装か。
  • その際、アクセストークンはclientプログラムで保持せず、毎回getTokenを使うとリフレッシュ等自動でやってくれる(はず)

3. self-backend <-> Firebase ... アクセストークン検証、uid(firebase user ID)の確認


// token の検証をしてuidを返す
function verifiedUid($idTokenString)
{
   if (empty($idTokenString)) {
       return '';
   }
   // firebase管理画面からadmimn jsonをDL、配置しておく
   $firebaseServiceJson = json_decode(file_get_contents('path/to/firebase/admin/sdk/settings.json'));
   // PSR16 Simple Cacheの実装であれば他のでも大丈夫そう。firebaseのpublic keyをキャッシュする用
   $cache = new \Symfony\Component\Cache\Simple\FilesystemCache();
   $keyStore = new \Firebase\Auth\Token\HttpKeyStore(null, $cache);
   $verifier = new \Firebase\Auth\Token\Verifier($firebaseServiceJson->project_id, $keyStore);

   $uid;
   try {
       $verifiedIdToken = $verifier->verifyIdToken($idTokenString);
       $uid = $verifiedIdToken->getClaim('sub'); // "uid"

       // なんらかのキャッシュ機構を使って毎回firebaseにverifyしないようにする方が良さそう
       $exp = $verifiedIdToken->getClaim('exp'); // expr

   } catch (\Firebase\Auth\Token\Exception\ExpiredToken $e) {
       var_dump($e);
   } catch (\Firebase\Auth\Token\Exception\IssuedInTheFuture $e) {
       var_dump($e);
   } catch (\Firebase\Auth\Token\Exception\InvalidToken $e) {
       var_dump($e);
   }
   
   return $uid;
}
  • 得られたuidはfirebase project単位でのユニーク値なので、この値を元に自前db等でデータ管理する。uidでの登録がなければ新規ユーザエントリ生成。あれば既存ユーザのログインとなる。
  • MySQLでのシンプルなテーブル例。uidの不可逆圧縮はした方が良いだろうか。した方がよりセキュアではある。
CREATE TABLE `users` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `uid` varchar(255) NOT NULL DEFAULT '',
  `nickname` varchar(255) NOT NULL DEFAULT '',
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uid` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

4. self-backend -> client ... 認証可否含めたレスポンスの返却

    1. に成功してればログイン済みユーザとなるし、そうでなければゲスト扱い。通常の会員サービスと変わらない

その他諸々

AWS Cognitoは?

Cognitoでも同じことできるだろうけど、用語も実装もfirebaseの方がわかりやすかったので未確認

利用料

2018.8現在のところ電話番号認証は1万/月まで無料。それ以降は有料プラン https://firebase.google.com/pricing/?hl=ja
それ以外のAuth機能は無料。
AdminSDK利用とかもしかしたら抜けてるポイントがあるかも?

instagram や自作認証機構、他のプロバイダーを使う。

カスタム認証を使って作る
https://firebase.google.com/docs/auth/ios/custom-auth
https://developers-jp.googleblog.com/2016/10/authenticate-your-firebase-users-with.html
https://github.com/search?q=firebase+instagram

firestoreやcloud sqlを使えば

この辺使うとするとgceやcloud functionも必要になってきそうで、S3やTranscoderやもろもろ乗り換える必要が出てきそうで、なかなか手が出ない。心理的ロックイン感。

データにより分けるのは良いかもしれない。ログやマスタデータのみfirestoreとかすると、firebaseの管理画面から閲覧修正できるので便利かも。

252
213
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
252
213

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?