Astro SSRでBasic認証
フツーにやろうとしたら結構つまづいたので備忘録的にメモっておきます。
早速ですが、答えから先に書いておきますね
---
const authorization = Astro.request.headers.get('authorization')
const pieces = authorization?.split(/\s+/g)
if(authorization) {
if(pieces) {
if(pieces[0] === 'Basic') {
const buffer = Buffer.from(pieces[1], 'base64')
const credentials = buffer.toString()
console.log(credentials)
const [username, password] = credentials.split(':')
if(username === import.meta.env.ADMIN_ID && password === import.meta.env.ADMIN_PASSWORD) {
Astro.response.status = 200
Astro.response.headers.delete('WWW-Authenticate')
Astro.response.headers.delete('Content-Length')
}
}
}
} else {
Astro.response.status = 401
Astro.response.headers.set('WWW-Authenticate','Basic realm="realm"')
Astro.response.headers.set('Content-Length','0')
}
---
<section class="content">
<p>Basic認証通過後に表示させたいコンテンツをここに書きます</p>
</section>
やってること
地道に、RequestからAuthorizationを抜き出し、それが存在しなければ未認証で、ヘッダーに要認証の情報を付加します。
Authorizationを抜き出し、さらにBasic認証であれば、Basic認証のクレデンシャルを復号し、usernameとpasswordに分離します。
Astroの環境変数に設定したユーザーネームとパスワードが合致していれば、ヘッダーの要認証情報を外し、200のステータスコードを返します。
なんてことはないです。ただこれだけのことです。
便利なライブラリないの?
せっかくAstroの内部ではNode.jsが使えるので、Basic認証用の便利なライブラリとかないのかな、と思われるかもしれません。
が、今回Basic認証をかけるにあたって色々トライしましたが、AstroのRequestの形がExpress等のそれらとは違うようで、普通には通りませんでした。
なので、地道に手作業で複合→認証しています。
複数のページや特定ディレクトリ下で全部BASIC認証かけたいんだけど?
そのニーズは理解できますが、今回の私は単一ページでの認証が必要だったのでこの実装となりました。
試してはいませんが、上記コードを外置きし、importしてやれば複数ページにわたって利用可能でしょう。
Apacheみたく特定ディレクトリ下で、ってなると、URLを読み出しして、特定の文字列がパスに含まれていたら、という条件分岐を書けばいけそうです。ぜひ誰か試して情報共有していただけると嬉しいです。
確認した環境
Local | Cloud |
---|---|
macOS Ventura | Vercel |
Node v16.16.0 | Node v16 |
参考情報
Basic認証を手で複合するやり方については、薄田様の記事を参考とさせていただきました。ありがとうございました。
また、AstroでRequest/Responseヘッダーを扱う方法については、公式のAPIドキュメントが参考になりました。公式大事。
Astroで環境変数を扱う方法については、こちら
dotenvとは、少し扱い方が異なりますので、Astro初心者の方は要注意です。
所感
まだまだAstroの情報が少ないのと、Node.jsの恩恵は預かれるも、Express等の既存フレームワークで育まれたノウハウはたちまちそのまま役立つわけではなかったので、若干遠回りしてしまいました。
自分だけが使うダッシュボードに認証をかけたかったのですが、そもそもAstroで認証を扱う情報が英語を含めても少なかったこと、ライブラリ等も未整備か発展途上でした。
Vercelでのデプロイが決定していたので、VercelのEdge Middlewareを使ったBasic認証についても試しましたが、うまくいかず。
結局何周かして、このように手作業で地道にやれば、あっさりできた、という感じです。
これからAstroにトライされる方の参考になれば幸いです。
Discussion