feat: 实现 Phase 3 JWT + 认证服务 #95
54
backend/internal/auth/middleware.go
Normal file
54
backend/internal/auth/middleware.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// contextKey 用于在 Gin context 中存储 Claims 的 key。
|
||||||
|
const (
|
||||||
|
ContextKeyUserID = "user_id"
|
||||||
|
ContextKeyUsername = "username"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthMiddleware 返回 Gin 中间件,从 Authorization: Bearer <token> 提取并校验 JWT。
|
||||||
|
// 校验成功后将 user_id 和 username 写入 Gin Context。
|
||||||
|
func AuthMiddleware(tokenMgr *TokenManager) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
authHeader := c.GetHeader("Authorization")
|
||||||
|
if authHeader == "" {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"code": "INVALID_TOKEN",
|
||||||
|
"message": "missing authorization header",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 Bearer token
|
||||||
|
parts := strings.SplitN(authHeader, " ", 2)
|
||||||
|
if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"code": "INVALID_TOKEN",
|
||||||
|
"message": "invalid authorization format",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := tokenMgr.ValidateAccess(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"code": "INVALID_TOKEN",
|
||||||
|
"message": "invalid or expired token",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将用户信息写入 context
|
||||||
|
c.Set(ContextKeyUserID, claims.UserID)
|
||||||
|
c.Set(ContextKeyUsername, claims.Username)
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user