ops_auth.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package middleware
  2. import (
  3. "context"
  4. "net/http"
  5. "strings"
  6. "cmr-backend/internal/apperr"
  7. "cmr-backend/internal/httpx"
  8. "cmr-backend/internal/platform/jwtx"
  9. )
  10. type opsAuthContextKey string
  11. const opsAuthKey opsAuthContextKey = "ops-auth"
  12. type OpsAuthContext struct {
  13. OpsUserID string
  14. OpsUserPublicID string
  15. RoleCode string
  16. }
  17. func NewOpsAuthMiddleware(jwtManager *jwtx.Manager, appEnv string) func(http.Handler) http.Handler {
  18. devContext := func(r *http.Request) *http.Request {
  19. ctx := context.WithValue(r.Context(), opsAuthKey, &OpsAuthContext{
  20. OpsUserID: "dev-ops-user",
  21. OpsUserPublicID: "ops_dev_console",
  22. RoleCode: "owner",
  23. })
  24. return r.WithContext(ctx)
  25. }
  26. return func(next http.Handler) http.Handler {
  27. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  28. authHeader := strings.TrimSpace(r.Header.Get("Authorization"))
  29. if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
  30. if appEnv != "production" {
  31. next.ServeHTTP(w, devContext(r))
  32. return
  33. }
  34. httpx.WriteError(w, apperr.New(http.StatusUnauthorized, "unauthorized", "missing bearer token"))
  35. return
  36. }
  37. token := strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer "))
  38. claims, err := jwtManager.ParseAccessToken(token)
  39. if err != nil {
  40. if appEnv != "production" {
  41. next.ServeHTTP(w, devContext(r))
  42. return
  43. }
  44. httpx.WriteError(w, apperr.New(http.StatusUnauthorized, "invalid_token", "invalid access token"))
  45. return
  46. }
  47. if claims.ActorType != "ops" {
  48. if appEnv != "production" {
  49. next.ServeHTTP(w, devContext(r))
  50. return
  51. }
  52. httpx.WriteError(w, apperr.New(http.StatusUnauthorized, "invalid_token", "invalid ops access token"))
  53. return
  54. }
  55. ctx := context.WithValue(r.Context(), opsAuthKey, &OpsAuthContext{
  56. OpsUserID: claims.UserID,
  57. OpsUserPublicID: claims.UserPublicID,
  58. RoleCode: claims.RoleCode,
  59. })
  60. next.ServeHTTP(w, r.WithContext(ctx))
  61. })
  62. }
  63. }
  64. func GetOpsAuthContext(ctx context.Context) *OpsAuthContext {
  65. auth, _ := ctx.Value(opsAuthKey).(*OpsAuthContext)
  66. return auth
  67. }