package router import ( "context" "net/http" "strings" "time" "chatapp3-golang/internal/common" "chatapp3-golang/internal/integration" "github.com/gin-gonic/gin" ) const authUserContextKey = "auth_user" type authGateway interface { AuthenticateToken(ctx context.Context, token string) (integration.UserCredential, error) AuthenticateConsoleToken(ctx context.Context, authorization string) (integration.ConsoleAccount, error) } // authMiddleware 校验用户 token,并把认证后的用户信息写入上下文。 func authMiddleware(javaClient authGateway) gin.HandlerFunc { return func(c *gin.Context) { authorization := strings.TrimSpace(c.GetHeader("Authorization")) if authorization == "" { writeError(c, common.NewAppError(http.StatusUnauthorized, "missing_authorization", "authorization is required")) c.Abort() return } token := trimBearer(authorization) ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second) defer cancel() credential, err := javaClient.AuthenticateToken(ctx, token) if err != nil { writeError(c, common.NewAppError(http.StatusUnauthorized, "invalid_token", err.Error())) c.Abort() return } c.Set(authUserContextKey, common.AuthUser{ UserID: int64(credential.UserID), SysOrigin: credential.SysOrigin, Token: token, Authorization: authorization, }) c.Next() } } // consoleAuthMiddleware 校验后台 console token,供后台管理类 Go 路由使用。 func consoleAuthMiddleware(javaClient authGateway) gin.HandlerFunc { return func(c *gin.Context) { authorization := strings.TrimSpace(c.GetHeader("Authorization")) if authorization == "" { writeError(c, common.NewAppError(http.StatusUnauthorized, "missing_authorization", "authorization is required")) c.Abort() return } ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second) defer cancel() if _, err := javaClient.AuthenticateConsoleToken(ctx, authorization); err != nil { writeError(c, common.NewAppError(http.StatusUnauthorized, "invalid_console_token", err.Error())) c.Abort() return } c.Next() } } // internalSecretMiddleware 校验内部回调密钥。 func internalSecretMiddleware(secret string) gin.HandlerFunc { return func(c *gin.Context) { if strings.TrimSpace(secret) == "" { c.Next() return } token := strings.TrimSpace(c.GetHeader("X-Internal-Token")) if token != secret { writeError(c, common.NewAppError(http.StatusUnauthorized, "invalid_internal_token", "internal token is invalid")) c.Abort() return } c.Next() } } // mustAuthUser 从 Gin 上下文读取已经通过鉴权的用户。 func mustAuthUser(c *gin.Context) common.AuthUser { value, exists := c.Get(authUserContextKey) if !exists { return common.AuthUser{} } user, _ := value.(common.AuthUser) return user } // trimBearer 去掉 Authorization 里的 Bearer 前缀。 func trimBearer(authorization string) string { if strings.HasPrefix(strings.ToLower(authorization), "bearer ") { return strings.TrimSpace(authorization[7:]) } return authorization } // resolveClientIP 解析请求来源 IP。 func resolveClientIP(c *gin.Context) string { if realIP := strings.TrimSpace(c.GetHeader("X-Real-IP")); realIP != "" { return realIP } if forwarded := strings.TrimSpace(c.GetHeader("X-Forwarded-For")); forwarded != "" { parts := strings.Split(forwarded, ",") if len(parts) > 0 { return strings.TrimSpace(parts[0]) } } return strings.TrimSpace(c.ClientIP()) }