✈️

AppEngineでBasic認証をしようとしてハマった話

2021/02/21に公開

先日、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認証の詳しい話はこちら

https://developer.mozilla.org/ja/docs/Web/HTTP/Authentication

でどうしたら解決したのか

正直なんで上記で動いてないのか、理由がわからないので早速結論だけ述べると、 BasicAuthForRealmの第二引数を空文字にする が正解の模様です。

BasicAuthForRealmの第二引数に渡しているのはRealmといって、認証で保護されている領域についての説明を入れることでアクセスしようとしてるクライアント側に伝えるための値なのですが、ここに文字を入れているとGAEにデプロイしたときにレスポンスヘッダーから削られてしまうという挙動を確認しました。
BasicAuthForRealmの実装を見てもらうとわかるのですが、ここを空文字にすると、Realmには Authentication Required という文字列が与えられるみたいなのですが、これだとうまく動きます。

おわりに

Realmに任意文字を入れた状態でも、ローカルではうまく動いていたので、GAE側の仕様で任意の文字がrealmに設定された WWW-Authentication ヘッダーがあると取り除かれてしまうという事なんでしょうかね?
この辺ドキュメントを一通り確認した限りでは、見つけられなかったのでどなたかの参考になれば幸いです。

今回試していないですが、他のランタイムでも同様の事象が発生する場合はRealmを Authentication Required にしてみるとことで解決するかもしれません。
お試しあれ。

Discussion