auth.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // Package middleware предоставляет middleware для HTTP-роутера.
  2. // Включает аутентификацию через JWT (AuthMiddleware), проверку ролей
  3. // (RoleMiddleware), in-memory rate limiter и Redis-based rate limiter
  4. // с настройками для auth, read, write и admin эндпоинтов.
  5. package middleware
  6. import (
  7. "context"
  8. "encoding/json"
  9. "net/http"
  10. "strings"
  11. "gogs.fxtmmsk.ru/foxtime/photoplaces/backend/internal/services"
  12. )
  13. type contextKey string
  14. const (
  15. UserIDKey contextKey = "user_id"
  16. UserRoleKey contextKey = "user_role"
  17. )
  18. func AuthMiddleware(authSvc *services.AuthService) func(http.Handler) http.Handler {
  19. return func(next http.Handler) http.Handler {
  20. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  21. authHeader := r.Header.Get("Authorization")
  22. if authHeader == "" {
  23. writeAuthError(w, "missing authorization header")
  24. return
  25. }
  26. parts := strings.SplitN(authHeader, " ", 2)
  27. if len(parts) != 2 || parts[0] != "Bearer" {
  28. writeAuthError(w, "invalid authorization format")
  29. return
  30. }
  31. claims, err := authSvc.ValidateAccessToken(parts[1])
  32. if err != nil {
  33. writeAuthError(w, "invalid or expired token")
  34. return
  35. }
  36. ctx := context.WithValue(r.Context(), UserIDKey, claims.UserID)
  37. ctx = context.WithValue(ctx, UserRoleKey, claims.Role)
  38. next.ServeHTTP(w, r.WithContext(ctx))
  39. })
  40. }
  41. }
  42. func RoleMiddleware(roles ...string) func(http.Handler) http.Handler {
  43. return func(next http.Handler) http.Handler {
  44. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  45. role, _ := r.Context().Value(UserRoleKey).(string)
  46. for _, allowed := range roles {
  47. if role == allowed {
  48. next.ServeHTTP(w, r)
  49. return
  50. }
  51. }
  52. writeAuthError(w, "insufficient permissions")
  53. })
  54. }
  55. }
  56. func GetUserID(ctx context.Context) string {
  57. v, _ := ctx.Value(UserIDKey).(string)
  58. return v
  59. }
  60. func GetUserRole(ctx context.Context) string {
  61. v, _ := ctx.Value(UserRoleKey).(string)
  62. return v
  63. }
  64. func writeAuthError(w http.ResponseWriter, msg string) {
  65. w.Header().Set("Content-Type", "application/json")
  66. w.WriteHeader(http.StatusUnauthorized)
  67. json.NewEncoder(w).Encode(map[string]string{"error": msg})
  68. }