79 lines
1.7 KiB
Go
79 lines
1.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"smoop-api/internal/crypto"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
func Auth(jwtMgr *crypto.JWTManager) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
h := c.GetHeader("Authorization")
|
|
if !strings.HasPrefix(h, "Bearer ") {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing bearer token"})
|
|
return
|
|
}
|
|
tok := strings.TrimPrefix(h, "Bearer ")
|
|
token, err := jwtMgr.Parse(tok)
|
|
if err != nil || !token.Valid {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
|
|
return
|
|
}
|
|
claims, _ := token.Claims.(jwt.MapClaims)
|
|
c.Set("claims", claims)
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func RequireRole(role string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
claims := MustClaims(c)
|
|
if ClaimRole(claims) != role {
|
|
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "forbidden"})
|
|
return
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// helpers used by handlers
|
|
func MustClaims(c *gin.Context) map[string]interface{} {
|
|
val, ok := c.Get("claims")
|
|
if !ok {
|
|
return jwt.MapClaims{}
|
|
}
|
|
switch t := val.(type) {
|
|
case jwt.MapClaims:
|
|
return t
|
|
case map[string]interface{}:
|
|
return jwt.MapClaims(t)
|
|
default:
|
|
return jwt.MapClaims{}
|
|
}
|
|
}
|
|
func ClaimUserID(claims map[string]interface{}) uint {
|
|
if claims == nil {
|
|
return 0
|
|
}
|
|
if v, ok := claims["sub"]; ok {
|
|
switch n := v.(type) {
|
|
case float64:
|
|
return uint(n)
|
|
case int:
|
|
return uint(n)
|
|
case int64:
|
|
return uint(n)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
func ClaimRole(claims map[string]interface{}) string {
|
|
if r, ok := claims["role"].(string); ok {
|
|
return r
|
|
}
|
|
return ""
|
|
}
|