ginでsessionを利用した認証ミドルウェアのテストコードの実装について
スマートな方法が思いつかず、力ずくな実装に。。
どなたかいい方法があるよっていう方は、コメントにてご教示ください。
よろしくお願いします。
テスト対象コード
auth_middleware.go
リクエストのセッション情報を取得し、認証が成功すれば次のハンドラーへ渡すのみ
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
session := sessions.Default(c)
authUserJson := session.Get("userInfo")
if authUserJson == nil {
c.JSON(401, domain.ErrorResponse{Message: "unauthorized"})
c.Abort()
return
}
var authUser domain.User
if err := json.Unmarshal([]byte(authUserJson.(string)), &authUser); err != nil {
c.JSON(401, domain.ErrorResponse{Message: "unauthorized"})
c.Abort()
return
}
c.Next()
}
}
テストコード
方針
- セッション発行用のエンドポイント(public)と、要認証のエンドポイント(protected)を用意
- publicへリクエスト発行し、そのレスポンスからセッションを取得
- 取得したセッションをprotectedのリクエストのクッキーとして設定し、リクエスト発行
- アサート
エンドポイント
public
セッション(ID)発行用のエンドポイント
// public route
public := r.Group("/public")
public.GET("", func(c *gin.Context) {
user := domain.User{
ID: 1,
Name: "test",
Email: "email",
Password: "password",
}
session := sessions.Default(c)
bUser, _ := json.Marshal(user)
session.Set("userInfo", string(bUser))
session.Save()
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
protected
認証用ミドルウェアを通過するエンドポイント
// protected route
protected := r.Group("/protected")
protected.Use(middleware.AuthMiddleware())
protected.GET("", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
リクエスト
publicへリクエスト発行し、そのレスポンスからセッションを取得
// request to the public endpoint
wPub := httptest.NewRecorder()
reqPub, _ := http.NewRequest("GET", "/public", nil)
reqPub.Header.Set("Content-Type", "application/json")
r.ServeHTTP(wPub, reqPub)
取得したセッションをprotectedのリクエストのクッキーとして設定し、リクエスト発行
// Extract session cookie from the response
sessionCookie := wPub.Header().Get("Set-Cookie")
assert.NotEmpty(t, sessionCookie, "Session cookie should not be empty")
// request to the protected endpoint
w2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/protected", nil)
req2.Header.Set("Content-Type", "application/json")
req2.Header.Set("Cookie", sessionCookie) // Attach session cookie
r.ServeHTTP(w2, req2)
テストコード全体
func TestAuthMiddleware(t *testing.T) {
gin.SetMode(gin.TestMode)
// session store
store := cookie.NewStore([]byte("secret"))
// router
r := gin.Default()
// session middleware
r.Use(sessions.Sessions("sessionid", store))
// public route
public := r.Group("/public")
public.GET("", func(c *gin.Context) {
user := domain.User{
ID: 1,
Name: "test",
Email: "email",
Password: "password",
}
session := sessions.Default(c)
bUser, _ := json.Marshal(user)
session.Set("userInfo", string(bUser))
session.Save()
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
// protected route
protected := r.Group("/protected")
protected.Use(middleware.AuthMiddleware())
protected.GET("", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
// test suite
t.Run("authentication success", func(t *testing.T) {
// request to the public endpoint
wPub := httptest.NewRecorder()
reqPub, _ := http.NewRequest("GET", "/public", nil)
reqPub.Header.Set("Content-Type", "application/json")
r.ServeHTTP(wPub, reqPub)
// extract session cookie from the response
sessionCookie := wPub.Header().Get("Set-Cookie")
assert.NotEmpty(t, sessionCookie, "Session cookie should not be empty")
// request to the protected endpoint
w2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/protected", nil)
req2.Header.Set("Content-Type", "application/json")
req2.Header.Set("Cookie", sessionCookie) // Attach session cookie
r.ServeHTTP(w2, req2)
// assert
assert.Equal(t, http.StatusOK, w2.Code)
assert.JSONEq(t, `{"message":"success"}`, w2.Body.String())
})
}