Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8896

Node.js + FirebaseでStatelessなAPIを実装する

$
0
0

留意事項

メモ書き程度なので詳細な説明は割愛します。

使う技術やサービス

  • Firebase Authentication
  • Node.js(FWはExpress)

Firebase側の準備

プロジェクト作成し、Authentication -> Sign-in MethodでGoogleを有効にしておきます。
Firebase側の準備はこれで終わりです。

実装

firebase-toolsをグローバルではなくローカルにインストールして進めていきます(ちょっと訳あり)。

準備

適当なディレクトリを作って

$ npm init -y$ npm i firebase-tools
$ npx firebase login

ログインが終わったら

$ npx firebase init

以下、ログ

?  Are you ready to proceed? (y/N)  y

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices.
 () Database: Deploy Firebase Realtime Database Rules
 () Firestore: Deploy rules and create indexes for Firestore
 (*) Functions: Configure and deploy Cloud Functions
 (*) Hosting: Configure and deploy Firebase Hosting sites
 () Storage: Deploy Cloud Storage security rules
 () Emulators: Set up local emulators for Firebase features

? Please select an option:
> Use an existing project
  Create a new project
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project

? Select a default Firebase project for this directory: (Use arrow keys)
> hogehoge-xxxxx (hogehoge)

=== Functions Setup

A functions directory will be created in your project with a Node.js
package pre-configured. Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? (Use arrow keys)
> JavaScript
  TypeScript

? Do you want to use ESLint to catch probable bugs and enforce style? (y/N) n
+  Wrote functions/package.json
+  Wrote functions/index.js
+  Wrote functions/.gitignore

? Do you want to install dependencies with npm now? (Y/n) y

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...
i  Writing gitignore file to .gitignore...

+  Firebase initialization complete!

バックエンド

functionsディレクトリ内で作業する。

$ npm i express cookie-parser

index.js

constadmin=require("firebase-admin");constcookieParser=require("cookie-parser")();constexpress=require("express");constfunctions=require("firebase-functions");constapi=express();admin.initializeApp();constvalidateFirebaseIdToken=async(req,res,next)=>{if((!req.headers.authorization||!req.headers.authorization.startsWith("Bearer "))&&!(req.cookies&&req.cookies.__session)){res.status(403).send("Unauthorized");return;}letidToken;if(req.headers.authorization&&req.headers.authorization.startsWith("Bearer ")){console.log('Found "Authorization" header');idToken=req.headers.authorization.split("Bearer ")[1];}elseif(req.cookies){console.log('Found "__session" cookie');idToken=req.cookies.__session;}else{res.status(403).send("Unauthorized");return;}try{constdecodedIdToken=awaitadmin.auth().verifyIdToken(idToken);console.log("ID Token correctly decoded",decodedIdToken);req.user=decodedIdToken;next();return;}catch(err){console.error(err);res.status(403).send("Unauthorized");return;}};api.use(cookieParser);api.use(validateFirebaseIdToken);api.get("/",(req,res)=>{res.status(200).send(JSON.stringify(req.user));});exports.api=functions.https.onRequest(api);

フロントエンド

publicディレクトリ内で作業する。

index.html

<!DOCTYPE html><htmllang="en"><head><title>Sample</title></head><body><buttonid="demo-sign-in-button"style="display: none;">
      Sign in with Google
    </button><buttonid="demo-sign-out-button"style="display: none;">
      Sign out
    </button><script src="/__/firebase/7.14.2/firebase-app.js"></script><script src="/__/firebase/7.14.2/firebase-auth.js"></script><script src="/__/firebase/init.js"></script><script src="index.js"></script></body></html>

index.js

document.addEventListener("DOMContentLoaded",function(){signInButton=document.getElementById("demo-sign-in-button");signOutButton=document.getElementById("demo-sign-out-button");signInButton.addEventListener("click",signIn);signOutButton.addEventListener("click",signOut);firebase.auth().onAuthStateChanged(onAuthStateChanged);});constonAuthStateChanged=(user)=>{if(user){console.info(user);signInButton.style.display="none";signOutButton.style.display="block";startFunctionsCookieRequest();}else{console.info("!user");signInButton.style.display="block";signOutButton.style.display="none";}};constsignIn=()=>{firebase.auth().signInWithPopup(newfirebase.auth.GoogleAuthProvider());};constsignOut=()=>{firebase.auth().signOut();document.cookie="__session=";};conststartFunctionsCookieRequest=()=>{firebase.auth().currentUser.getIdToken(true).then(function(token){document.cookie="__session="+token+";max-age=86400";});};

プロダクト開発ではAuthorization: Bearer <token>を使うようにしよう(手抜き)。

動作確認

プロジェクトルートディレクトリで作業する。

$ npx firebase emulators:start

Hostingは5000番ポート、Functionsは5001番ポートで起動しますのでそれぞれ確認。


Viewing all articles
Browse latest Browse all 8896

Trending Articles