🛡️
Remix on Vercel で無料で Basic 認証を全体にかける方法
これはなに
Remix で作ったプロトタイプを Vercel にデプロイして全ルートを対象に Basic 認証をかけたくていろいろ試行錯誤したので、その備忘録になります。
結論
-
app/entry.server.tsx
でWWW-Authenticate: Basic
のHTTPヘッダを返すように設定 -
app/root.tsx
に定義した loader で認証確認しRoot component で結果に応じて出し分ける
ポイントは 1. と 2. に分けてやることです。 root.tsx の headers で WWW-Authenticate を返すようにしてる記事もあったのですが、それだと実際の Response Header にヘッダが反映されず、動作しません。
デモ
ユーザ名: admin
パスワード: password
ソースコード
entry.server.tsx で WWW-Authenticate ヘッダを返す設定
entry.server.tsx
import type { EntryContext } from '@remix-run/node'
import { RemixServer } from '@remix-run/react'
import { renderToString } from 'react-dom/server'
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
)
responseHeaders.set('Content-Type', 'text/html')
responseHeaders.set('WWW-Authenticate', 'basic') // Basic認証のヘッダを全レスポンスで返す
return new Response('<!DOCTYPE html>' + markup, {
status: responseStatusCode,
headers: responseHeaders,
})
}
root.tsx の loader での認証確認処理。
root.tsx
const isAuthorized = (request: Request) => {
const header = request.headers.get('Authorization')
if (!header) return false
const base64 = header.replace('Basic ', '')
const [username, password] = Buffer.from(base64, 'base64')
.toString()
.split(':')
return username === 'admin' && password === 'password'
}
export const loader = ({ request }: LoaderArgs) => {
if (isAuthorized(request)) {
return json({ authorized: true })
} else {
return json({ authorized: false }, { status: 401 })
}
}
root.tsx の root コンポーネントで結果に応じて出し分け
root.tsx
export default function App() {
const { authorized } = useLoaderData<typeof loader>()
if (!authorized) {
return <>Authorization Required</>
}
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
)
}
remix たのしい〜。
東京でミートアップをしたいな〜
Discussion