2026-06-09 15:42:52 +08:00

126 lines
3.5 KiB
Go
Raw Permalink 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 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())
}