auth.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package middleware
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net/http"
  6. "strings"
  7. "github.com/photoplaces/backend/internal/services"
  8. )
  9. type contextKey string
  10. const (
  11. UserIDKey contextKey = "user_id"
  12. UserRoleKey contextKey = "user_role"
  13. )
  14. func AuthMiddleware(authSvc *services.AuthService) func(http.Handler) http.Handler {
  15. return func(next http.Handler) http.Handler {
  16. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  17. authHeader := r.Header.Get("Authorization")
  18. if authHeader == "" {
  19. writeAuthError(w, "missing authorization header")
  20. return
  21. }
  22. parts := strings.SplitN(authHeader, " ", 2)
  23. if len(parts) != 2 || parts[0] != "Bearer" {
  24. writeAuthError(w, "invalid authorization format")
  25. return
  26. }
  27. claims, err := authSvc.ValidateAccessToken(parts[1])
  28. if err != nil {
  29. writeAuthError(w, "invalid or expired token")
  30. return
  31. }
  32. ctx := context.WithValue(r.Context(), UserIDKey, claims.UserID)
  33. ctx = context.WithValue(ctx, UserRoleKey, claims.Role)
  34. next.ServeHTTP(w, r.WithContext(ctx))
  35. })
  36. }
  37. }
  38. func RoleMiddleware(roles ...string) func(http.Handler) http.Handler {
  39. return func(next http.Handler) http.Handler {
  40. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  41. role := r.Context().Value(UserRoleKey).(string)
  42. for _, allowed := range roles {
  43. if role == allowed {
  44. next.ServeHTTP(w, r)
  45. return
  46. }
  47. }
  48. writeAuthError(w, "insufficient permissions")
  49. })
  50. }
  51. }
  52. func GetUserID(ctx context.Context) string {
  53. v, _ := ctx.Value(UserIDKey).(string)
  54. return v
  55. }
  56. func GetUserRole(ctx context.Context) string {
  57. v, _ := ctx.Value(UserRoleKey).(string)
  58. return v
  59. }
  60. func writeAuthError(w http.ResponseWriter, msg string) {
  61. w.Header().Set("Content-Type", "application/json")
  62. w.WriteHeader(http.StatusUnauthorized)
  63. json.NewEncoder(w).Encode(map[string]string{"error": msg})
  64. }