af2366acb5
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)
32 lines
1.1 KiB
Go
32 lines
1.1 KiB
Go
package infra
|
|
|
|
import "net/http"
|
|
|
|
// RBACMiddleware retorna un Middleware que verifica que el usuario autenticado
|
|
// tenga un permiso concreto. Requiere que JWTMiddleware se ejecute antes en la
|
|
// chain (lee las claims del context). El rol se extrae de claims.Custom["role"].
|
|
// Responde 403 si el rol no tiene el permiso; 401 si no hay claims en el context.
|
|
func RBACMiddleware(roles []Role, required Permission) Middleware {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
claims, ok := JWTClaimsFromContext(r.Context())
|
|
if !ok {
|
|
HTTPErrorResponse(w, HTTPError{
|
|
Status: http.StatusUnauthorized, Code: "no_claims",
|
|
Message: "rbac_middleware requiere jwt_middleware antes en la chain",
|
|
})
|
|
return
|
|
}
|
|
roleName, _ := claims.Custom["role"].(string)
|
|
if roleName == "" || !RBACCheck(roles, roleName, required) {
|
|
HTTPErrorResponse(w, HTTPError{
|
|
Status: http.StatusForbidden, Code: "forbidden",
|
|
Message: "no tienes permiso para esta accion",
|
|
})
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|