@iquadras/shared-guards
v0.0.2
Published
Guards compartilhados para autenticação e autorização JWT no ecossistema iQuadras (NestJS, React)
Maintainers
Readme
@iquadras/shared-guards
Guards compartilhados para autenticação e autorização JWT no ecossistema iQuadras.
Geral
Hierarquia de permissões
- superAdmin — Acesso total ao sistema (admin iQuadras)
- isAdmin na organização — Acesso total naquela organização (dono do centro)
- Módulos — Acesso apenas aos módulos em
permissions[].modules
Módulos disponíveis
| Módulo | Descrição |
|--------|-----------|
| MODULES.BOOKING | Reserva de quadras |
| MODULES.CLASSES | Aulas |
| MODULES.REPLAY | Replay |
Funções de permissão (core)
isSuperAdmin(user)— É super admin?isOrgAdmin(user, organizationId)— É admin da org ou super admin?hasModuleAccess(user, organizationId, module)— Tem acesso ao módulo na org?
Header do JWT
O token deve ser enviado em x-auth-access-token.
NestJS
Instalação
npm install @iquadras/shared-guards @nestjs/jwtConfiguração
1. Defina JWT_SECRET no .env
2. Importe o módulo no AppModule:
import { SharedGuardsModule } from '@iquadras/shared-guards';
@Module({
imports: [SharedGuardsModule.forRoot()],
})
export class AppModule {}3. Remova o JwtModule de outros módulos — o SharedGuardsModule já registra globalmente.
4. (Opcional) Logs em main.ts:
const app = await NestFactory.create(AppModule, {
logger: ['error', 'warn', 'log', 'debug'],
});Uso
Rotas são públicas por padrão. Use decorators para proteger.
| Decorator | Quem tem acesso |
|-----------|-----------------|
| @RequireAnyAuth() | Qualquer usuário autenticado |
| @RequireSuperAdminAuth() | Apenas super admins |
| @RequireOrganizationAdminAuth({ organizationIdSource }) | Super admins ou admin da organização |
| @RequireModuleAuth(module, { organizationIdSource }) | Super admin, admin da org ou usuário com o módulo |
OrganizationId: @RequireOrganizationAdminAuth e @RequireModuleAuth exigem organizationIdSource — informe sempre de onde virá o ID (params, query ou body):
import { RequireAnyAuth, GetUser, RequireModuleAuth, RequireOrganizationAdminAuth, RequireSuperAdminAuth, MODULES } from '@iquadras/shared-guards';
@Controller('organizations/:organizationId/reservas')
export class ReservasController {
@Get(':id') findOne(@Param('id') id: string) { /* público */ }
// organizationId no path (params)
@Post() @RequireModuleAuth(MODULES.BOOKING, { organizationIdSource: 'params.organizationId' }) create(@Body() dto: CreateReservaDto) { }
// organizationId no body
@Post('outra-rota') @RequireModuleAuth(MODULES.BOOKING, { organizationIdSource: 'body.organizationId' }) createFromBody(@Body() dto: Dto) { }
// organizationId na query
@Get() @RequireOrganizationAdminAuth({ organizationIdSource: 'query.orgId' }) list(@Query() q: { orgId: string }) { }
@Patch(':id/estornar') @RequireOrganizationAdminAuth({ organizationIdSource: 'params.organizationId' }) estornar(@Param('id') id: string) { }
@Delete(':id') @RequireSuperAdminAuth() remove(@Param('id') id: string) { }
}Paths comuns: params.organizationId, params.orgId, query.organizationId, query.orgId, body.organizationId, body.orgId. Pode passar array para tentar na ordem: { organizationIdSource: ['body.organizationId', 'query.orgId'] }.
Quando o organizationId é descoberto no processo (ex: buscando um recurso pelo id e obtendo a org dele), valide manualmente no controller com as funções do core:
import { isOrgAdmin, hasModuleAccess, GetUser } from '@iquadras/shared-guards';
import type { JwtPayload } from '@iquadras/shared-guards';
// No controller, após buscar o recurso:
const reserva = await this.reservasService.findOne(id);
const user = request.user as JwtPayload;
if (!isOrgAdmin(user, reserva.organizationId)) {
throw new ForbiddenException('Sem permissão');
}React
Instalação
npm install @iquadras/shared-guardsUso
As funções recebem o token e fazem o decode internamente (sem validar — no client não temos o secret):
import {
isSuperAdmin,
isOrgAdmin,
hasModuleAccess,
MODULES,
} from '@iquadras/shared-guards/react';
// No componente — token do localStorage, contexto de auth, etc.
const token = getTokenFromStorage(); // sua função
const canCreate = hasModuleAccess(token, orgId, MODULES.BOOKING);
const isAdmin = isOrgAdmin(token, orgId);
const isSuper = isSuperAdmin(token);Atenção: O decode no React não valida a assinatura. Use apenas para UI (exibir/esconder elementos). A validação real ocorre na API.
Core
Para usar apenas a lógica (sem framework) — ex: Adonis, Express, etc.:
import {
isSuperAdmin,
isOrgAdmin,
hasModuleAccess,
decodeToken,
MODULES,
} from '@iquadras/shared-guards/core';