認証だけfirebase使いたい場合の考察。
要求
- ユーザ認証(登録・ログイン)はfirebaseに任せたい。
- ユーザデータはAWS RDS等別途のシステムで管理したい。
全体像
- Firebase <-> client ... ユーザ登録・ログイン(アクセストークンの発行)
- client -> self-backend ... アクセストークンの送信
- self-backend <-> Firebase ... アクセストークン検証、uid(firebase user ID)の確認
- 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)の確認
- Firebaes Admin SDKを使ってアクセストークンを検証し、uidを得る
- https://firebase.google.com/docs/admin/setup?hl=ja
- 例えばphp(サードパーティ製) -> https://github.com/kreait/firebase-php
// 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 ... 認証可否含めたレスポンスの返却
-
- に成功してればログイン済みユーザとなるし、そうでなければゲスト扱い。通常の会員サービスと変わらない
その他諸々
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の管理画面から閲覧修正できるので便利かも。