Basic 認証で Cookie を使う
◆ ダイアログを出すなど認証時のやり取りは Basic 認証の仕組みで行う
◆ 成功時は Cookie を使って管理
◆ Basic 認証自体は成功させず 401 を返して Cookie をセット
◆ その後のログイン判断は Cookie で行う
◆ 成功時は Cookie を使って管理
◆ Basic 認証自体は成功させず 401 を返して Cookie をセット
◆ その後のログイン判断は Cookie で行う
以前 Chrome で 401 レスポンスを受け取ったときに response body を表示してくれないという記事を書きました
半年くらいたってますし そろそろ修正されたりしないかなと試してみると 表示できました
401 レスポンスでやりたかったことがあったのでやってみることにしました
Basic 認証の仕組みで id と password 送信するけど ログイン状態は Cookie で管理するというものがあれば便利そうです
ということで作ったものがこちらです
それ以外は常に ok というレスポンスです
user という Cookie に名前が入っていればそのユーザでログイン中とみなし 入っていなければ未ログインとみなします
偽装し放題なので実際には Cookie に署名したり工夫がいりますがここでは省きます
/auth 内にアクセスがあった場合 Cookie を見てログイン中なら Cookie に含まれるユーザ名を表示します
未ログインの場合は 401 で Basic 認証を必要というレスポンスを返します
id と password が送られてきたらチェックします
ログインに成功した場合ですが Basic 認証を成功させたくはないので 401 を返します
初回と同じように WWW-Authenticate ヘッダーを送るとまたダイアログが出てしまい ログイン失敗時と同じになるので WWW-Authenticate ヘッダーは送りません
こうすると失敗になりダイアログが出ません
このときに一緒に Set-Cookie ヘッダーを送り Cookie にログイン情報をもたせます
ログイン成功時は Cookie にログイン情報が残り Basic 認証は失敗したという扱いです
これだと画面が Basic 認証に失敗した状態になるのでリロードし再度リクエストを送ります
今度は Cookie があるのでログイン済みのページが表示できます
リロードは script タグで location.reload() の JavaScript で実行してますが meta タグとかでもできます
ログアウトは /auth/logout にアクセスしたときで Cookie のログイン情報を削除します
このやり方では Basic 認証が成功してブラウザに Basic 認証の情報が残ることがないようにしましたが ここまで特殊なことしなくても Basic 認証はそのまま普通に使って 認証成功時に Cookie に追加情報を保存するでも十分な気はします
半年くらいたってますし そろそろ修正されたりしないかなと試してみると 表示できました
401 レスポンスでやりたかったことがあったのでやってみることにしました
Basic 認証で Cookie を使う
Basic 認証ってブラウザでダイアログを出してくれますし 楽ではありますが Cookie を使うものに比べて 認証後の扱いづらさがあると思いますBasic 認証の仕組みで id と password 送信するけど ログイン状態は Cookie で管理するというものがあれば便利そうです
ということで作ったものがこちらです
const http = require("http")
const realm = "xyz"
const basic_user = "abcd"
const basic_pass = "123"
http.createServer((req, res) => {
if (!req.url.startsWith("/auth")) {
res.end("ok")
return
}
if (req.url === "/auth/logout") {
res.setHeader("Set-Cookie", "user=; path=/")
res.end("logout")
return
}
const cookie = Object.fromEntries(
(req.headers.cookie || "").split(";").map((item) => item.split("="))
)
if (cookie.user) {
res.statusCode = 200
res.end(`You are ${cookie.user}.`)
return
}
const auth = req.headers.authorization
if (auth) {
const str = Buffer.from(auth.split(" ")[1], "base64").toString()
const [user, pass] = str.split(":")
if (basic_user === user && basic_pass === pass) {
res.statusCode = 401
res.setHeader("Set-Cookie", `user=${user}; path=/`)
res.end(`<script>location.reload()</script>`)
} else {
res.statusCode = 401
res.setHeader("WWW-Authenticate", `Basic realm="${realm}"`)
res.end("Unauthorized")
}
} else {
res.statusCode = 401
res.setHeader("WWW-Authenticate", `Basic realm="${realm}"`)
res.end("Unauthorized")
}
}).listen(8000)
仕組み
対象とするのは /auth の中だけにしていますそれ以外は常に ok というレスポンスです
user という Cookie に名前が入っていればそのユーザでログイン中とみなし 入っていなければ未ログインとみなします
偽装し放題なので実際には Cookie に署名したり工夫がいりますがここでは省きます
/auth 内にアクセスがあった場合 Cookie を見てログイン中なら Cookie に含まれるユーザ名を表示します
未ログインの場合は 401 で Basic 認証を必要というレスポンスを返します
id と password が送られてきたらチェックします
ログインに成功した場合ですが Basic 認証を成功させたくはないので 401 を返します
初回と同じように WWW-Authenticate ヘッダーを送るとまたダイアログが出てしまい ログイン失敗時と同じになるので WWW-Authenticate ヘッダーは送りません
こうすると失敗になりダイアログが出ません
このときに一緒に Set-Cookie ヘッダーを送り Cookie にログイン情報をもたせます
ログイン成功時は Cookie にログイン情報が残り Basic 認証は失敗したという扱いです
これだと画面が Basic 認証に失敗した状態になるのでリロードし再度リクエストを送ります
今度は Cookie があるのでログイン済みのページが表示できます
リロードは script タグで location.reload() の JavaScript で実行してますが meta タグとかでもできます
ログアウトは /auth/logout にアクセスしたときで Cookie のログイン情報を削除します
このやり方では Basic 認証が成功してブラウザに Basic 認証の情報が残ることがないようにしましたが ここまで特殊なことしなくても Basic 認証はそのまま普通に使って 認証成功時に Cookie に追加情報を保存するでも十分な気はします