AppEngineでBasic認証をしようとしてハマった話
先日、AppEngineにデプロイしたアプリケーションにBasic認証を設定しようとして、ハマったので事の顛末を記しておこうと思います。(今時Basic認証を使いたい機会もそう多くないとは思いますが😅)
前提
GAEのランタイムはGAE Standard go114で、その上で動くアプリケーションには gin を使用して構築したWebサーバを使用していました。
Basic認証にはginに付属している BasicAuthForRealm というミドルウェアを使用していました。
実装はだいたいこんなかんじです。
package main
import (
"github.com/gin-gonic/gin"
"github.com/uutarou10/example/handler"
)
func main() {
r := gin.Default()
admin := r.Group("/admin", gin.BasicAuthForRealm(map[string]string{
"userId": "password",
}, "管理者ページだよ〜"))
{
admin.GET("/", handler.Admin)
}
r.Run()
}
こいつをデプロイしてあげて /admin
へ接続すると401が返ってくるのですが、その際本来必要な WWW-Authentication
ヘッダーが付与されていないためにブラウザが認証ダイアログを出してくれません。
(本来のBasic認証は、Authorization
ヘッダーを含まずにリクエストをしたとき、レスポンスヘッダーに WWW-Authentication
ヘッダーを含めて返す事で、認証方式をクライアント側に伝えるというフローで行われる)
Basic認証の詳しい話はこちら
でどうしたら解決したのか
正直なんで上記で動いてないのか、理由がわからないので早速結論だけ述べると、 BasicAuthForRealmの第二引数を空文字にする が正解の模様です。
BasicAuthForRealmの第二引数に渡しているのはRealmといって、認証で保護されている領域についての説明を入れることでアクセスしようとしてるクライアント側に伝えるための値なのですが、ここに文字を入れているとGAEにデプロイしたときにレスポンスヘッダーから削られてしまうという挙動を確認しました。
BasicAuthForRealmの実装を見てもらうとわかるのですが、ここを空文字にすると、Realmには Authentication Required
という文字列が与えられるみたいなのですが、これだとうまく動きます。
おわりに
Realmに任意文字を入れた状態でも、ローカルではうまく動いていたので、GAE側の仕様で任意の文字がrealmに設定された WWW-Authentication
ヘッダーがあると取り除かれてしまうという事なんでしょうかね?
この辺ドキュメントを一通り確認した限りでは、見つけられなかったのでどなたかの参考になれば幸いです。
今回試していないですが、他のランタイムでも同様の事象が発生する場合はRealmを Authentication Required
にしてみるとことで解決するかもしれません。
お試しあれ。
Discussion