f46fde3656
Fase 5 del issue 0010 — RBAC y middlewares de auth.
- rbac_check es pura: solo recorre la matriz roles/permisos
- jwt_middleware extrae token del header Authorization: Bearer, valida e
inyecta claims en el context con una key privada (jwtCtxKey struct{})
- rbac_middleware requiere jwt_middleware antes; lee role de claims.Custom
- Helper JWTClaimsFromContext para acceder a las claims desde handlers
- 401 claro si RBAC se usa sin JWT antes (code: no_claims)
43 lines
2.2 KiB
Markdown
43 lines
2.2 KiB
Markdown
---
|
|
name: jwt_middleware
|
|
kind: function
|
|
lang: go
|
|
domain: infra
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "func JWTMiddleware(secret string) Middleware"
|
|
description: "Middleware HTTP que extrae el JWT del header Authorization: Bearer y valida con JWTValidate. Inyecta las claims en el context del request (recuperables con JWTClaimsFromContext). Responde 401 si falta el header, formato incorrecto o token invalido."
|
|
tags: [jwt, auth, middleware, http, server, infra]
|
|
uses_functions: [jwt_validate_go_infra, http_error_response_go_infra]
|
|
uses_types: [JWTClaims_go_infra, Middleware_go_infra, HTTPError_go_infra]
|
|
returns: [Middleware_go_infra]
|
|
returns_optional: false
|
|
error_type: error_go_core
|
|
imports: [context, net/http, strings]
|
|
params:
|
|
- name: secret
|
|
desc: "clave HMAC para JWTValidate. Debe ser la misma usada en JWTGenerate"
|
|
output: "Middleware que protege handlers con validacion JWT. Las claims se inyectan en r.Context() con una key privada"
|
|
tested: true
|
|
tests: ["pasa con token valido", "401 sin header Authorization", "401 con formato distinto de Bearer", "401 con token invalido", "claims accesibles via JWTClaimsFromContext"]
|
|
test_file_path: "functions/infra/jwt_middleware_test.go"
|
|
file_path: "functions/infra/jwt_middleware.go"
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```go
|
|
protected := HTTPMiddlewareChain(
|
|
HTTPLoggerMiddleware(os.Stderr),
|
|
JWTMiddleware(os.Getenv("JWT_SECRET")),
|
|
)
|
|
mux.Handle("GET /api/me", protected(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
claims, _ := JWTClaimsFromContext(r.Context())
|
|
HTTPJSONResponse(w, 200, map[string]string{"user_id": claims.Subject})
|
|
})))
|
|
```
|
|
|
|
## Notas
|
|
|
|
Impura — lee headers y modifica el request. Expone el helper JWTClaimsFromContext(ctx) que devuelve (JWTClaims, bool) — el bool permite distinguir "no autenticado" de "subject vacio". Usa `context.WithValue` con una key de tipo privado `jwtCtxKey struct{}` para evitar colisiones con otros middlewares. Solo soporta cabecera `Authorization: Bearer`; para leer token desde cookie se crearia un middleware separado. En las respuestas 401 no se da detalle del motivo (token expirado vs firma invalida) para no filtrar informacion, el motivo real esta en los logs si se compone con HTTPLoggerMiddleware.
|