2026-04-30 02:30:32 +08:00

61 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package http
import (
"net/http"
"hyapp/pkg/logx"
"hyapp/services/gateway-service/internal/auth"
)
// apiHandler 包装所有 gateway 业务 HTTP API 的公共入口能力。
// 顺序必须是 request_id -> auth -> handler保证鉴权失败也能返回可追踪 request_id。
func apiHandler(jwtVerifier *auth.Verifier, next http.HandlerFunc) http.Handler {
return withRequestID(withAccessLog(withAuth(jwtVerifier, next)))
}
// profileAPIHandler 包装必须完成注册资料才能访问的业务 API。
// 三方登录后未完成资料的用户已经有合法 token但不能进入房间、IM、RTC 或付费链路。
func profileAPIHandler(jwtVerifier *auth.Verifier, next http.HandlerFunc) http.Handler {
return withRequestID(withAccessLog(withAuth(jwtVerifier, requireCompletedProfile(next))))
}
// publicAPIHandler 包装不需要 access token 的业务 API。
// 登录注册链路仍然有 request_id但不能要求用户已经有 access token。
func publicAPIHandler(next http.HandlerFunc) http.Handler {
return withRequestID(withAccessLog(next))
}
// withAccessLog 统一记录 gateway 业务 API 的请求体、响应体、状态码和耗时。
// healthcheck 不经过该 middleware避免探活日志淹没业务调用。
func withAccessLog(next http.Handler) http.Handler {
return logx.HTTPMiddleware("gateway-service", requestIDFromContext, next)
}
// withAuth 在 transport 层完成鉴权失败响应写入。
// auth 包只返回身份校验结果,避免底层鉴权模块绑定 gateway 的 JSON envelope。
func withAuth(jwtVerifier *auth.Verifier, next http.HandlerFunc) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
claims, err := jwtVerifier.Verify(request.Header.Get("Authorization"))
if err != nil {
writeError(writer, request, http.StatusUnauthorized, codeUnauthorized, "unauthorized")
return
}
ctx := auth.WithClaims(request.Context(), claims)
next.ServeHTTP(writer, request.WithContext(ctx))
})
}
// requireCompletedProfile 在 gateway 层执行外部准入门禁。
// 这里故意不访问 user-service依赖 access token 快照,避免所有高频房间入口同步打用户服务。
func requireCompletedProfile(next http.HandlerFunc) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
if !auth.ProfileCompletedFromContext(request.Context()) {
writeError(writer, request, http.StatusForbidden, codeProfileRequired, "profile required")
return
}
next.ServeHTTP(writer, request)
}
}