61 lines
2.5 KiB
Go
61 lines
2.5 KiB
Go
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)
|
||
}
|
||
}
|