Files
backend/internal/api/middleware.go

90 lines
2.5 KiB
Go
Raw 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 api
import (
"context"
"net/http"
"os"
"strings"
"github.com/golang-jwt/jwt/v5"
)
type contextKey string
const ClaimsContextKey = contextKey("claims")
// AuthMiddleware проверяет JWT токен и добавляет claims в контекст запроса.
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var tokenString string
// 1. Проверяем заголовок Authorization
authHeader := r.Header.Get("Authorization")
if authHeader != "" {
tokenString = strings.TrimPrefix(authHeader, "Bearer ")
if tokenString == authHeader { // Не было префикса Bearer
http.Error(w, "Invalid token format", http.StatusUnauthorized)
return
}
}
// 2. Если заголовка нет, проверяем параметр query (для WebSocket)
if tokenString == "" {
tokenString = r.URL.Query().Get("token")
}
if tokenString == "" {
http.Error(w, "Authorization required", http.StatusUnauthorized)
return
}
jwtSecret := []byte(os.Getenv("JWT_SECRET_KEY"))
if len(jwtSecret) == 0 {
http.Error(w, "JWT secret not configured", http.StatusInternalServerError)
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, jwt.ErrSignatureInvalid
}
return jwtSecret, nil
})
if err != nil || !token.Valid {
http.Error(w, "Invalid or expired token", http.StatusUnauthorized)
return
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
http.Error(w, "Invalid token claims", http.StatusUnauthorized)
return
}
// Добавляем claims в контекст
ctx := context.WithValue(r.Context(), ClaimsContextKey, claims)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// AdminMiddleware проверяет, что пользователь аутентифицирован и имеет роль 'admin'.
func AdminMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Получаем claims из контекста
claims, ok := r.Context().Value(ClaimsContextKey).(jwt.MapClaims)
if !ok {
http.Error(w, "Could not get claims from context", http.StatusInternalServerError)
return
}
role, ok := claims["role"].(string)
if !ok || role != "admin" {
http.Error(w, "Forbidden: insufficient permissions", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}