見出し画像

~Firebase Authentication~ TypeScript & React & Firebase で何かつくってみる17


タイトルが長いせいで「通知」などでサブタイトルが省略されてしまう. 全部同じに見えてしまって不便だ.
そこで今更ながら「サブタイトルを先に持ってくる」という策を講じてみた.

Firebase Authentication

Firebase Authentication については敢えてこれまで避けてきた.
理由は 2 つ.
・ なんか面倒そう.
・ 個人情報集めるほどすごいサービスを作るつもりはない.

だが最近 匿名認証 という機能があることを知った. これは
「ログインは任意でよいが 個人の識別はしたい」
という私のニーズに合っているように見える.

そこで以下を参考に匿名認証を有効にしてみる.

クラウド側はここに書いてあるとおりに行った.

匿名認証の実装

基本的なことは公式に書いてある.

これに従ってコードを修正する.

src/App.tsx

function App() {
 const [user, setUser] = React.useState<firebase.User|null>(null);

 React.useEffect(() => {
   firebase.auth().signInAnonymously().catch(function(error) {
     console.log(`${error.code}, ${error.message}`);
   });
 
   firebase.auth().onAuthStateChanged(user => {
      setUser(user);
   });
 }, []);

 return (
   <BrowserRouter>
     <div className='App'>
       <div className='App-header'>
         { user ? `こんにちは ${user.displayName||'ゲスト'} さん` : `ログインしていません`}
         <h2>Playing Cards</h2>
       </div>
       <Switch>
       <Route exact path='/' component={RoomBuilder}/>
       <Route path='/rooms/:roomId' component={CardGame}/>
       <Route path='*' children={<h1>Not Found</h1>} />
       </Switch>
     </div>
   </BrowserRouter>
 );
}

firebase.auth().signInAnonymously() が 匿名認証を行うAPIだ. 匿名なのでパスワードやメールアドレスといった情報を渡す必要はない.引数なしですぐ呼び出せる.
戻り値が Promise なのでそこから結果を得ることもできるのだろうが, 大抵のサンプルコードではそれを無視している.

代わりに firebase.auth().onAuthStateChanged() を使って結果を得る.
結果というより認証情報の変更を監視する API らしいので, 確かにこちらを実装するほうがいくつかの処理が一箇所で済みそうだ.
user firebase.User | null 型で ログアウト状態のとき null らしい.

画像1

ログインできたっぽい.
Firebase Console も確認する.

FireShot Capture 033 - card-game-field - Authentication - Firebase コンソール_ - console.firebase.google.com

1回実行しただけでアカウントが2つできてしまった.
これはどうも, 初期実装では React.useEffect() を使っていなかったためだ. 認証処理をこれでくるんでおかなかったため, 関数が再描画のたびに何度も呼び出された結果 2こ作られてしまったようだ.

以下の記事では Firebase Authentication をイマドキの React で実装した例を紹介してくれている. 匿名認証ではないが非常に参考になったので紹介しておく.


firestore.rules への適用

認証機能を使えば firestore に対して「認証されていないユーザーからのアクセスを禁止」できる. 
もっとも, 匿名認証でどれほどセキュリティ的に意味があるかはよくわからないが.

firestore.rules

   match /rooms/{roomId} {
     allow create, read, delete: if isAuthenticated();

     match /fields/{deckId} {
       allow create, update: if isAuthenticated();
       allow delete: if isAuthenticated() 
                     && resource.data.cards.size() == 0;
     }

        :
        :
     function isAuthenticated() {
       return request.auth != null;
     }

紹介するほど大したことはしていない.
isAuthenticated() 関数を作ってすべての条件に加えた. この辺のノウハウは以下のブログを参考にしている.

「すべてに追加」とは言うが, ヌケモレがありそうで怖い.

簡易テストとして, ソースコードのログイン部分をコメントアウトした上で, Firebase Console からアカウント削除し, 未ログイン状態にしてからコマンドが認証エラーになることを確認.

一度アカウントを紐付けてしまうと勝手にログインしてしまうようで, アカウント消さないと未ログイン状態にできなかった. (細かい条件は不明)

この記事が気に入ったらサポートをしてみませんか?