内容としてはこれの発展形です。特定のフォルダ内に別なNuxt.jsプロジェクトが入っており、そこをIP制限します。
/index.html // baseurl のリクエストをさばくファイル
/_nuxt // baseurl にリクエストされた時に読み込まれるスクリプト
/restrict // baseurl/restrict にきたアクセスを IP 制限したい
/index.html // baseurl/restrict のリクエストをさばくファイル
/_nuxt // baseurl/restrict にリクエストされた時に読み込まれるスクリプト
TL;DR
認証の窓口となる express サーバーを Cloud Functions で動かして、静的ファイル(今回はビルドされたNuxt.js)をホスティングする。
前提条件
/restrict
配下にアクセスが有った場合のみ IP 制限を実施し、それ以外については制限をかけない。
詳細
IP 制限する Cloud Functions を用意
Firebase は express のインスタンスを onRequest
で渡せばよしなに動いてくれるので、IP 制限する express サーバーを用意します。こちらを参考にしました。
https://qiita.com/otakky/items/1363e7b4c706dc9cd096
import * as functions from 'firebase-functions';
import * as requestIp from 'request-ip';
import * as express from 'express';
// ここにアクセスを許可したいIPを記載
const allowedIps = ['192.168.1.1', ...];
const app = express();
app.all('/*', (req, res, next) => {
const clientIp = requestIp.getClientIp(req);
const isAllowed = allowedIps.indexOf(clientIp) !== -1;
if (!isAllowed) {
res.status(statusCode).send(`You cannot access here. Please check your IP. `);
} else {
next();
}
});
// ホスティングしたい静的ファイルが格納されたフォルダを指定
app.use('/restrict', express.static(`${__dirname}/../restrict/`));
export const ipAuth = functions.https.onRequest(app);
Firebase Hosting の設定を変更
rewrite
ルールを使って、経由させたい関数を指定する。
"hosting": {
/* 中略 */
"rewrites": [
{
"source": "/restrict{,/**}",
"function": "ipAuth"
},
{
"source": "**",
"destination": "/index.html"
}
]
/* 中略 */
}
全体を IP 制限したいのであれば、 2つ目のルールの "destination"
を "function": "ipAuth"
にしてあげればよいです。
Nuxt.js の設定
Nuxt.js のビルド結果は絶対パスで生成されるため、ローカルで直接開けば正常に動きますが、ホスティングすると https://BASEURL/_nuxt
を参照してしまい、 /restrict
向けのビルド結果を参照できません。それを是正するため、 baseルートを指定します。
export default {
// 略
router: {
base: '/restrict/'
},
// 略
}
これで、dist
にビルドされる index.html
の script タグの参照先は /restrict/_nuxt/hogehoge...js
になり、ホスティングされても正しく解釈されるようになります。
デプロイ前調整
/restrict
でアクセスされる Nuxt.js のビルド結果を IP 制限用 Cloud Functions の静的ファイルが指し示す場所 ${__dirname}/../restrict/
にコピーしてください。
デプロイ
通常通り firebase deploy
で大丈夫です。
ハマりどころ
express-ipfilter を使ってはいけない
何故か Firebase の内部 IP を拾ってしまうようで、どこからアクセスしても 自分のグローバル IP ではないもいの(しかも IPv6 ) を拾ってしまいフィルター出来ませんでした。
express サーバーのパスの指定漏れ
app.use('/restrict', express.static(`${__dirname}/../public/restrict/`));
// ~~~~~~~~~ これ
全体をIP制限したい場合は未指定 app.use(express.static(...))
でいいのですが、今回は /restrict
にアクセスした場合のみ制限するため、これがないとエラーになります。
Hosting の設定
rewrites
ルールで "source": "/restrict"
と書いてしまうと、/restrict/_nuxt/hogehoge...js
すら /restrict
にリダイレクトされてしまい、内容が index.html
になっている JS が配信されてしまいます。
その他
同じ感じで BASIC 認証も出来ます。express で BASIC 認証する方法を調べれば良いと思います。
デメリット
アクセスする度に Function execution started
と Function execution took xx ms, finished with status code: 200
のログが出力されるので Stackdriverが 汚されます。別にログ取らなくていいんだけどなぁ。。。
それでは!
2020/10/1追記: 他のやり方
身もふたもないですが、プロキシサーバーを用意して、IP制限したいコンテンツだけ別サーバーでホスティングするというのが多分最適解です。
この記事を書くに至ったプロジェクトはプロキシサーバー方式に変更する予定です。