Kosaku Kurino

Kosaku Kurino

【Firebase】自作API(API Gateway + Lambda)でFirebaseのAuthenticationを利用する方法

概要

Firebase Authenticationに登録されているどのアカウントか判断し、なにか処理をおこなうAPIをAPI Gateway(AWS)lambda(AWS)を利用して作成します。

せっかくなのでlambda(AWS)では新機能のレイヤーの使い方も説明しちゃおうと思います。

対象者

Firebase Authenticationの機能を知っている人 Firebase Authenticationを利用したAPIを作成したい人

Firebase Admin SDKについて

自作APIでアカウントの判断をするためには、firebaseではなくfirebase-adminが必要になります。 firebases-adminでは、アカウントが発行するトークンをもとに、どのアカウントか判断できる機能があります。この機能を利用することで自作APIを作成していきます。

Firebaseプロジェクトの作成

Firebase consoleを開き、新規プロジェクトを作成します。 開発のAuthenticationを開き、Googleを有効にします。

キャプチャ.JPG

プロジェクトの設定のサービスアカウント画面を開きます。 Project Overviewの右の馬車アイコンから、プロジェクトの設定を選択し、サービスアカウントを開きましょう。

キャプチャ.JPG

Firebase Admin SDKの新しい秘密鍵の生成からjsonファイルをダウンロードしましょう。databaseURLの値は後で使うのでメモしておきます。

キャプチャ.JPG

firebase consoleですることは終わりです。

APIの作成

イメージ

firebase-sdkTokenの発行、 firebase-admin-sdkTokenをチェックします。

キャプチャ.JPG

API環境の準備(AWS)

ローカル環境にAPIを作るのもいいのですが、最終的にはAWSを利用したり、Azureを利用してAPIを公開していくものだと思っているので、いきなりAWS上に環境作ります。

Layerの作成

今回はfirebase-adminを使用します。 firebase-adminをLambdaで利用できるようにするため、Layerを作成してみましょう。Layerはソースコードの共有が可能になる機能です。Lambda関数内でLayerを読み込むことでfirebase-adminが即座に利用可能になります。

PC上にnodejsという名前でフォルダを作成し、フォルダ内でfirebase-adminをインストールします。

※Layerは読み込むファイルのパスが決まっているため、フォルダ構成はnodejs/node_modules/にしなければなりません。ほかの構成でも読み込めますが詳しくはこちらをご覧ください。

library version
firebase-admin v6.3.0
npm install firebase-admin

AWSマネジメントコンソール画面でLambdaのLayersを選択し、 新規Layerをランタイム Node.js 8.10で、先ほど作成したnodejsフォルダをzip化してS3経由でアップロードし、作成します。

※S3経由でのアプロード方法がわからない方はGoogleで調べてください。

Lambda関数の作成

AWSマネジメントコンソール画面でLambdaの関数を選択し、 新規関数をランタイム Node.js 8.10で作成します。

Layersを選択し、レイヤーの追加から先ほど作成したLayerを追加します。

キャプチャ.png

次に、Lambda関数本体を書いていきます。

const admin = require('firebase-admin');
const firebaseDatabaseEndpoint = process.env.FIREBASE_DATABASE_ENDPOINT;

const serviceAccount = require('./admin.json');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: firebaseDatabaseEndpoint,
})

exports.handler = async (event, context, callback) => {
    // firebase uid 検証
    const uid = await admin.auth().verifyIdToken(event.token)
        .then((decodedToken) => {
            return decodedToken.uid;
        })
        .catch((error) => {
            console.log(error);
            return null;
        })
   
    if(uid) {
        // 検証に成功している場合実行する処理
        console.log('hello firebase');
        
        const response = {
            statusCode: 200,
            body: { 
                message: 'verify token success.',
                uid: uid
            },
        };
        
        return response;
    }
    else {
        const response = {
            statusCode: 500,
            body: {
                message: 'verify token failure.'
            },
        };
        
        return response;
    }
};

firebaseのプロジェクトの設定をします。

firebaseDatabaseEndpointには、さきほどメモしておいたdatabaseURLを環境変数で設定します。serviceAccountには、さきほどダウンロードした秘密鍵をadmin.jsonとしてアップロードし読み込みます。

const admin = require('firebase-admin');
const firebaseDatabaseEndpoint = process.env.FIREBASE_DATABASE_ENDPOINT;

const serviceAccount = require('./admin.json');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: firebaseDatabaseEndpoint,
})

キャプチャ.JPG

firebase-adminauthverifyIdToken関数でTokenの検証を行います。検証に成功した場合は、アカウント毎に設定されているuidを獲得できます。

// firebase uid 検証
const uid = await admin.auth().verifyIdToken(event.token)
    .then((decodedToken) => {
        return decodedToken.uid;
    })
    .catch((error) => {
        console.log(error);
        return null;
    })

次に、uidの有無で処理を分けて、最後にレスポンスを返すようにします。

if(uid) {
    // 検証に成功している場合実行する処理
    console.log('hello firebase');
        
    const response = {
        statusCode: 200,
        body: { 
            message: 'verify token success.',
            uid: uid
        },
    };
        
    return response;
}
else {
    const response = {
        statusCode: 500,
        body: {
            message: 'verify token failure.'
        },
    };
        
    return response;
}

これでLambdaは完成です。

API Gatewayの作成

AWSマネジメントコンソール画面でAPI Gatewayの新規APIを作成します。作成したAPIのリソースでアクション→メソッドの作成よりGETを追加します。

統合タイプはLambda 関数で、Lambda関数の欄は先ほど作成した関数を入力します。

キャプチャ.JPG

はじめに、FirebaseのTokenを送信するカスタムヘッダーを設定します。

メソッドリクエストを選択し、HTTPリクエストヘッダーにX-FIREBASE-TOKENを追加、リクエストの検証を「クエリ文字列パラメータおよびヘッダーの検証」に変更します。

キャプチャ.JPG

次に、ヘッダーのX-FIREBASE-TOKENをLambda関数で受け取れるように設定します。

統合リクエストを選択し、マッピングテンプレートのリクエスト本文のパススルーを「テンプレートが定義されていない場合」に変更します。 application/jsonでマッピングテンプレートを追加します。 Lambda関数内でevent.tokenX-FIREBASE-TOKENの値を取得できるようになります。

{
    "token": "$input.params('X-FIREBASE-TOKEN')"
}
キャプチャ.JPG

リソースでアクション→APIのデプロイより、ステージを新しく作成しAPIを完成させましょう。

キャプチャ.JPG

APIの作成は完了です。

APIの利用

クライエントサイドは情報が溢れているため端折らせてもらいます。 ※React Firebase SNS認証等で調べればたくさん出てきます。

firebaseaxiosをインストールします。

npm install firebase
npm install axios
library    version
firebase v5.7.0
axios v0.18.0

configファイルの準備

Firebase consoleを開き、プロジェクトを開きます。 開発のAuthenticationを開き、ウェブ設定を押して、configを確認します。

スクリーンショット 2018-12-15 1.31.13.png

configファイルを作成します。

export const config = {
    apiKey: "xxxx",
    authDomain: "xxxx",
    databaseURL: "xxxx",
    projectId: "xxxx",
    storageBucket: "xxxx",
    messagingSenderId: "xxxx"
  };

ログインの例

GoogleとFacebookのログインの仕方を書いています。

import * as firebase from 'firebase'
import { config } from './config' // config読み込み
firebase.initializeApp(config)

const googleProvider = new firebase.auth.GoogleAuthProvider()
const facebookProvider = new firebase.auth.FacebookAuthProvider()

const auth = firebase.auth()

// Google Login
const authGoogle = () => {
    auth.signInWithRedirect(googleProvider)
}

// Facebook Login
const authFacebook = () => {
    auth.signInWithRedirect(facebookProvider)
}

Token取得の例

ログイン時のアカウントのTokenの取得方法を書いています。

import * as firebase from 'firebase'
import { config } from './config' // config読み込み
firebase.initializeApp(config)

const auth = firebase.auth()

auth.currentUser.getIdToken(true).then((idToken) => {
    const token = idToken
    console.log(token)
})
.catch(err => {
    console.log(err)
})

リクエスト送信の例

X-FIREBASE-TOKENに先ほど取得した、Tokenを設置し、GETリクエストを送信します。

import axios from 'axios'

const lambdaEndpoint = 'xxxx'
const token = 'xxxx'

axios.get(lambdaEndpoint, {} ,{
    headers: {
        'X-FIREBASE-TOKEN': token
    }
})
.then(res => {
    console.log(res.data)
})
.catch(err => {
    console.log(err)
})

これらのコードを利用して、Reactアプリでもサクッと作って試してみましょう。

最後に

firebaseのSNS認証機能はかなり強力で、爆速でアプリ開発できます。 ただアプリ開発おいて、DBは自前でもちたい等、firebaseのサービスだけで完結できるとは限らないです。 そのため、今回はfirebaseのサービス以外と連携させるためのAPIの作成方法を紹介させていただきました。