GoでMeilisearchをリバースプロキシ
instant-searchはMeilisearchが公開されているのを前提で動くのですが、Meilisearchを非公開にしたいときや、独自認証を挟みたい時はどうするの?という時のTips。Goで。
ポイントは
- GoでMeilisearchの
/indexes/:index_uid/search
へのリバースプロキシを書いてその中で独自の認証を処理する - 独自認証したい場合はinstant-searchのinit時に指定するMeilisearchのキーにTokenを併記する(Authorizationヘッダーに載る)
- レスポンスの
Content-Encoding: gzip
も忘れずに
client のinitialize
const searchClient = instantMeiliSearch(
'https://your-backend.tld'
meiliApiKey + ';' + yourApiToken, // 今回はセミコロン区切りで併記
)
backend
func main() {
...
router.POST("/indexes/:index_uid/search", meiliProxy) // 使うルーティングライブラリに応じてカキカエテ
...
}
func meiliProxy(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
indexUID := params.ByName("index_uid")
// https://your-meilisearch.tld/indexes/hogehogeindex/search
endpoint, err := url.JoinPath(os.Getenv("MEILI_HOST"), "indexes", indexUID, "search")
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
req, err := http.NewRequest(r.Method, endpoint, r.Body)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
req.Header = r.Header.Clone() // instant-searchから飛んできたHeaderをクローン
// meilisearchapikey;dokujitokenhogehogehogehogehoge のような形式のAuthorizationを分割して返しているだけ
meiliToken, dokujiToken, err := parseMeiliAuthorizationHeader(r.Header.Get("Authorization"))
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
// dokujiTokenに含まれるパーミッションの確認
claims := dokujiToken.GetClaims()
if !claims.HasPermission("read") && !claims.HasPermission("write") {
w.WriteHeader(http.StatusUnauthorized)
return
}
req.Header.Set("Authorization", "Bearer "+meiliToken)
res, err := client.Do(req)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
body, err := io.ReadAll(res.Body)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
defer res.Body.Close()
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Encoding", "gzip") // これも必要
w.WriteHeader(res.StatusCode)
w.Write(body)
}
- 測ってないけどクライアント側の使用感は体感影響無し
- 独自認証の部分はもしかしたらそのうち対応するかも?関連: https://github.com/meilisearch/instant-meilisearch/issues/928