LoginSignup
17
17

More than 3 years have passed since last update.

Firebase HostingでSPA(React)表示 + Basic認証を同時に実現する

Last updated at Posted at 2019-11-19

Firebase HostingにはBasic認証かけたりIP制限等の機能が標準では提供されていません。
それを実現するためにはFunctionsの機能と連携して実現します。

方針

  • まず、リクエストをpublicではなくfunctionsの(app)関数にリクエストを仕向ける。
  • rewrite先の関数で何を表示するかを決める。
  • 表示するまでに認証等の処理をかますことにより必要な処理を行う。

作業場所の準備

作業場所を作ってfirebase initをします。

cd
mkdir rewrite
cd rewrite
firebase init

FunctionsとHostingを選択。
下記のようなフォルダが作成されるはずです。

.
├── firebase.json
├── functions
└── public

まず、public内のindex.htmlを削除しておきます。ファイルが存在するとそちらが優先して表示されてしまうようです。

次にfunctionsでcreate-react-appを実行します。
いろいろ編集したらbuildして、buildフォルダを作成しておきます。

cd functions
create-react-app react-app
yarn build

公開サイト/ファイルはpublicではなく、functions/react-app/build/(index.html)に変更していきます。

実装

それぞれのファイルを編集していきます。

firebase.json(rewrite設定)

まず、firebase.jsonのrewritesを設定して全て(**)のリクエストをfunction, appに転送します。

firebase.json
{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "app"
      }
    ]
  }
}

SPAをホスティング

認証を設定する前に、そもそもSPAアプリをfunction経由で表示する設定をします。
大きくは2つの設定を。

index.js
const functions = require('firebase-functions');
const express = require('express');
const path = require('path');


const app = express();

//とりあえずスタティックの場所指定
app.use(express.static(__dirname + '/react-app/build/'));

//それ以外の時もindex.htmlへ
app.all('*', (req, res, next) => {
    res.sendFile(path.resolve(__dirname, 'react-app/build/index.html'));
})

exports.app = functions.https.onRequest(app);

deploy

一旦ここでdeployしておきます。

firebase deploy

reactの標準画面が見えればOKです。
一見、Hostingを利用しているのと変わりませんが、functions経由で表示されています。

Basic認証

Basic認証を設定します。まずモジュールをインストールします。

npm isntall --save basic-auth-connect

ここではID=admin, password=passwordに設定しています。

index.js
const functions = require('firebase-functions');
const express = require('express');
const path = require('path');
+const basicAuth = require('basic-auth-connect');

const app = express();

+app.use(basicAuth('admin','password'));

//とりあえずスタティックの場所指定
app.use(express.static(__dirname + '/react-app/build/'));

//それ以外の時もindex.htmlへ
app.all('*', (req, res, next) => {
    res.sendFile(path.resolve(__dirname, 'react-app/build/index.html'));
})

exports.app = functions.https.onRequest(app);
firebase deploy

IP制限

ついでにIP制限をも追加設定してみます。

index.js
const functions = require('firebase-functions');
const express = require('express');
const path = require('path');
const basicAuth = require('basic-auth-connect');
+const requestIp = require('request-ip');

//許可IP 43.233.87.238
+const allowedIps = ['43.233.87.238'];

const app = express();

//basic認証
app.use(basicAuth('admin', 'password'));

//IPチェック
+app.all('*', (req, res, next) => {
+    //IPチェック
+    const clientIp = requestIp.getClientIp(req);
+    const isAllowed = allowedIps.indexOf(clientIp) !== -1;
+    if (!isAllowed) {
+        res.send("You can't access this site.")
+    } else {
+        next();
+    }
+})

//とりあえずスタティックの場所指定
app.use(express.static(__dirname + '/react-app/build/'));

//それ以外の時もindex.htmlへ
app.all('*', (req, res, next) => {
    res.sendFile(path.resolve(__dirname, 'react-app/build/index.html'));
})

exports.app = functions.https.onRequest(app);

参考

17
17
0

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