material_manage_system/internal/middleware/auth.go
2026-09-16 23:30:25 +08:00

150 lines
3.1 KiB
Go

package middleware
import (
"strings"
"github.com/gin-gonic/gin"
"github.com/wmms/wmms/internal/service"
"github.com/wmms/wmms/pkg/response"
)
const (
AuthorizationHeader = "Authorization"
BearerPrefix = "Bearer "
UserIDKey = "user_id"
UsernameKey = "username"
RolesKey = "roles"
)
// AuthMiddleware validates JWT tokens
func AuthMiddleware() gin.HandlerFunc {
authSvc := service.NewAuthService()
return func(c *gin.Context) {
authHeader := c.GetHeader(AuthorizationHeader)
if authHeader == "" {
response.Unauthorized(c, "missing authorization header")
c.Abort()
return
}
if !strings.HasPrefix(authHeader, BearerPrefix) {
response.Unauthorized(c, "invalid authorization format")
c.Abort()
return
}
tokenString := strings.TrimPrefix(authHeader, BearerPrefix)
token, err := authSvc.ValidateToken(tokenString)
if err != nil {
response.Unauthorized(c, "invalid or expired token")
c.Abort()
return
}
// Set user info in context
c.Set(UserIDKey, token.UserID)
c.Set(UsernameKey, token.Username)
c.Set(RolesKey, token.Roles)
c.Next()
}
}
// AdminOnly middleware restricts access to admin role only
func AdminOnly() gin.HandlerFunc {
return func(c *gin.Context) {
roles, exists := c.Get(RolesKey)
if !exists {
response.Unauthorized(c, "unauthorized")
c.Abort()
return
}
if !hasRole(roles, "super_admin") {
response.Forbidden(c, "admin access required")
c.Abort()
return
}
c.Next()
}
}
// GetCurrentUserID returns the current user's ID from context
func GetCurrentUserID(c *gin.Context) int64 {
if id, exists := c.Get(UserIDKey); exists {
return id.(int64)
}
return 0
}
// GetCurrentUsername returns the current username from context
func GetCurrentUsername(c *gin.Context) string {
if username, exists := c.Get(UsernameKey); exists {
return username.(string)
}
return ""
}
// GetCurrentRoles returns the authenticated role-code snapshot. This is the
// extension point for replacing token roles with a request-time principal.
func GetCurrentRoles(c *gin.Context) []string {
if roles, exists := c.Get(RolesKey); exists {
if values, ok := roles.([]string); ok {
return values
}
}
return []string{}
}
func IsSuperAdmin(c *gin.Context) bool {
return hasRole(GetCurrentRoles(c), "super_admin")
}
func hasRole(value interface{}, expected string) bool {
roles, ok := value.([]string)
if !ok {
return false
}
for _, role := range roles {
if role == expected {
return true
}
}
return false
}
// OptionalAuth middleware extracts user info if token is present but doesn't require it
func OptionalAuth() gin.HandlerFunc {
authSvc := service.NewAuthService()
return func(c *gin.Context) {
authHeader := c.GetHeader(AuthorizationHeader)
if authHeader == "" {
c.Next()
return
}
if !strings.HasPrefix(authHeader, BearerPrefix) {
c.Next()
return
}
tokenString := strings.TrimPrefix(authHeader, BearerPrefix)
token, err := authSvc.ValidateToken(tokenString)
if err != nil {
c.Next()
return
}
c.Set(UserIDKey, token.UserID)
c.Set(UsernameKey, token.Username)
c.Set(RolesKey, token.Roles)
c.Next()
}
}