12
12

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 3 years have passed since last update.

Firebase Authenticationで認証コードログインを実現する

Last updated at Posted at 2020-01-26

やりたいこと

  • 個人ごとにユーザ管理したりするほどの要件ではない
  • かといってサイトにアクセスできた人全員が使えてしまうのは困るので簡易ログインはほしい
  • ログイン機能は自分では実装したくない

→「認証コード」を使ったログイン機能をFirebase Authenticationで実現したい

できたもの

ezgif.com-resize.gif

4行で

  1. 匿名認証してUIDをゲット
  2. 1のUIDと入力された認証コードをCloud Functionsに投げる
  3. 認証コードが正しければ2のUIDにCustom claimを付与
  4. 以後のログインチェックはCustom claimで判定

フロー

image.png

実装

本記事はJSで実装していますが言語は特に重要ではないため、その他の言語でも同じように実装できると思います。要所を抜粋しているので単純にコピペしても動作しません。

フロントエンド

①〜④、⑧の部分です。

login.js
// 匿名認証でログインしてUIDを取得
const userCredential = await firebase.auth().signInAnonymously()
const uid = userCredential.user.uid

// 認証コードが正しければそのユーザーにカスタムクレイムを付与する関数を呼び出し
const authWithCode = firebase.functions().httpsCallable('authWithCode')
const result = await authWithCode({ uid, verifyCode: this.code })
// カスタムクレイム付与後、強制的にトークンをリフレッシュ
await firebase.auth().currentUser.getIdToken(true)

Vue.jsのrouterを使用する場合は以下のようにログイン判定ができます。

router.js
firebase.auth().onAuthStateChanged(async function (user) {
  if (user) {
    let getIdTokenResult = await user.getIdTokenResult()
    if (getIdTokenResult.claims.codeVerified) {
      // カスタムクレイムで認証成功したとき
      next()
    } else {
      // 匿名認証はしているけどカスタムクレイムが付与されていないとき
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    }
  } else {
    // 匿名認証すらしていないとき
    next({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  }
})

コード検証関数

⑤〜⑦の部分です。

codeVerify.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const VERIFY_CODE = '0112'

exports.authWithCode = functions.https.onCall(async (request, response) => {
  // 設定された認証コードと送られてきた認証コードが一致するか判定
  if(request.verifyCode === VERIFY_CODE) {
    try{
      // Custom claimを付与
      await admin.auth().setCustomUserClaims(request.uid, {codeVerified: true})
      return { status: 'ok', message: '認証しました。' }
    }catch(error){
      return { status: 'error', message: 'ログイン処理に失敗しました。' }
    }
  }else{
    return { status: 'error', message: '認証コードが正しくありません。' }
  }
});

Firestoreルール

データソースのルールはCustom claimで判定するようにするとコード認証したユーザーのみ操作が許可できます。

rule.js
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read: if request.auth.token.codeVerified == true;
      allow write: if false;
    }
  }
}

参考

[公式]Custom claimについて
https://firebase.google.com/docs/auth/admin/custom-claims?hl=ja#best_practices_for_custom_claims
https://firebase.google.com/docs/auth/admin/custom-claims?hl=ja

Callable HTTPS Functionについて
https://miso-soup3.hateblo.jp/entry/2018/05/22/215453

12
12
1

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
12
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?