Go で Middleware を作り Context にデータを入れて次の処理に引き継ぐ
Go で Middleware を作り、その中で読み込んだデータを Context に入れて次の処理に引き継ぐ。
開発環境
- go version go1.17.5 linux/amd64
本文
Go で認証必須の API を保護する Middleware を作成し、その Middleware 内で読み込んだデータを Context に入れて API 本体の処理に引き継ぐ方法についてメモする。
Middleware
今回の例では、認証状態は “auth-session” というセッションから uid が取得できるかどうかで判定する。
package middleware
import (
"context"
"net/http"
"github.com/pkg/errors"
"github.com/k1350/sololog/internal/session"
)
type AuthContext map[string]interface{}
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// ここは各自の実装で認証状態が保存されているセッションを取得する
s, err := session.Store.Get(r, "auth-session")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
uid := s.Values["uid"]
if uid == nil {
// uid が取得できなかった場合は 401 エラーを返す
w.WriteHeader(http.StatusUnauthorized)
return
}
// API 本体の処理に引き継ぎたい値を context にセット
data := AuthContext{
"uid": uid.(string),
}
ctx := context.WithValue(r.Context(), "auth", data)
// r.WithContext で値を引き継ぐ
next.ServeHTTP(w, r.WithContext(ctx))
}
}
Middleware の使用
下記のように http.HandleFunc 内で作成した Middleware で本体の関数を包む。
また Middleware から引き継いだ値は r.Context() から読み取ることができる。
package main
import (
"fmt"
"log"
"net/http"
// 作成した Middleware
"github.com/k1350/sololog/internal/middleware"
)
func main() {
http.HandleFunc("/", middleware.AuthMiddleware(HelloServer))
http.ListenAndServe(":8000", nil)
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
// Middleware で Context に入れたデータを取り出す
data := r.Context().Value("auth").(middleware.AuthContext)["uid"]
log.Println(data)
fmt.Fprintf(w, "Hello, world!")
}