222 lines
3.5 KiB
Markdown
222 lines
3.5 KiB
Markdown
# Identity Backend Architecture
|
|
|
|
## Objetivo del módulo `identity`
|
|
|
|
`identity` sustituye progresivamente al módulo legacy `auth`.
|
|
|
|
Responsabilidades previstas:
|
|
|
|
- cuentas autenticables
|
|
- login/password
|
|
- access token
|
|
- refresh token rotado
|
|
- logout
|
|
- sesión actual
|
|
- empresas accesibles
|
|
- memberships
|
|
- roles
|
|
- permisos
|
|
- autorización futura
|
|
|
|
## Dominio mínimo creado
|
|
|
|
Agregados principales:
|
|
|
|
```txt
|
|
Account
|
|
Company
|
|
CompanyMembership
|
|
Role
|
|
RefreshToken
|
|
```
|
|
|
|
## Value Objects reutilizados
|
|
|
|
Desde `@repo/rdx-ddd`:
|
|
|
|
```txt
|
|
UniqueID
|
|
LanguageCode
|
|
Name
|
|
TextValue
|
|
UtcDate
|
|
EmailAddress
|
|
URLAddress
|
|
```
|
|
|
|
VOs específicos de `identity`:
|
|
|
|
```txt
|
|
PasswordHash
|
|
RefreshTokenHash
|
|
RoleCode
|
|
AccountStatus
|
|
CompanyStatus
|
|
CompanyMembershipStatus
|
|
```
|
|
|
|
## Seguridad
|
|
|
|
Servicios definidos:
|
|
|
|
```txt
|
|
IPasswordHasher
|
|
IAccessTokenIssuer
|
|
IAccessTokenVerifier
|
|
IRefreshTokenGenerator
|
|
IRefreshTokenHasher
|
|
```
|
|
|
|
Implementaciones actuales:
|
|
|
|
```txt
|
|
BcryptPasswordHasher
|
|
JsonWebTokenAccessTokenIssuer
|
|
JsonWebTokenAccessTokenVerifier
|
|
CryptoRefreshTokenGenerator
|
|
Sha256RefreshTokenHasher
|
|
```
|
|
|
|
Decisiones:
|
|
|
|
- password hashing con `bcrypt` en V1.
|
|
- access token JWT con `accountId` y `email`.
|
|
- refresh token aleatorio con `crypto.randomBytes`.
|
|
- refresh token persistido solo como hash SHA-256.
|
|
- no incluir `companyId`, roles ni permisos en access token.
|
|
|
|
## Persistencia mínima
|
|
|
|
Tablas/modelos creados:
|
|
|
|
```txt
|
|
identity_accounts
|
|
identity_refresh_tokens
|
|
```
|
|
|
|
Repositorios:
|
|
|
|
```txt
|
|
IAccountRepository
|
|
IRefreshTokenRepository
|
|
SequelizeAccountRepository
|
|
SequelizeRefreshTokenRepository
|
|
```
|
|
|
|
## Servicios públicos del módulo
|
|
|
|
`identity` registra un servicio público:
|
|
|
|
```txt
|
|
identity:general
|
|
```
|
|
|
|
Incluye:
|
|
|
|
```ts
|
|
auth.authenticatedOnly(): RequestHandler[];
|
|
auth.tenantRequired(): RequestHandler[];
|
|
```
|
|
|
|
Pero los consumidores no deberían usar directamente `identity:general` en routers.
|
|
|
|
Deben usar los builders públicos:
|
|
|
|
```ts
|
|
requireIdentityAuthenticated(params: StartParams): RequestHandler[];
|
|
requireIdentityTenant(params: StartParams): RequestHandler[];
|
|
```
|
|
|
|
## Uso correcto en routers
|
|
|
|
```ts
|
|
import { requireIdentityTenant } from "@erp/identity/api";
|
|
|
|
export function buildSomeRoutes(params: StartParams) {
|
|
const router = Router();
|
|
|
|
router.use(...requireIdentityTenant(params));
|
|
|
|
return router;
|
|
}
|
|
```
|
|
|
|
## Shape actual de `req.user`
|
|
|
|
```ts
|
|
{
|
|
userId: UniqueID;
|
|
email?: EmailAddress;
|
|
companyId?: UniqueID;
|
|
roles?: string[];
|
|
}
|
|
```
|
|
|
|
Compatibilidad provisional:
|
|
|
|
- `roles` puede ser `[]`.
|
|
- `companyId` viene de `X-Company-Id`.
|
|
- `companySlug` no debe depender de auth.
|
|
|
|
## Prohibiciones de diseño
|
|
|
|
No usar en módulos consumidores:
|
|
|
|
```ts
|
|
IdentityInternalDeps;
|
|
authenticateUserDependencies;
|
|
getInternal("identity");
|
|
```
|
|
|
|
No crear:
|
|
|
|
```txt
|
|
<module>-auth-middlewares.ts
|
|
```
|
|
|
|
como patrón estable.
|
|
|
|
No añadir a access token:
|
|
|
|
```txt
|
|
companyId
|
|
roles
|
|
permissions
|
|
companySlug
|
|
```
|
|
|
|
## Permisos
|
|
|
|
Cada módulo define sus propios permisos.
|
|
|
|
`core` contiene contratos transversales mínimos:
|
|
|
|
```ts
|
|
export type PermissionCode = string;
|
|
|
|
export type PermissionDefinition = {
|
|
code: PermissionCode;
|
|
module: string;
|
|
description: string;
|
|
};
|
|
```
|
|
|
|
`identity` define solo sus permisos propios:
|
|
|
|
```txt
|
|
identity:companies:update
|
|
identity:roles:read
|
|
identity:roles:create
|
|
identity:roles:update
|
|
identity:roles:delete
|
|
identity:company-users:read
|
|
identity:company-users:update-roles
|
|
identity:company-users:disable
|
|
identity:company-users:enable
|
|
identity:permissions:read
|
|
```
|
|
|
|
`Role.permissionCodes` usa `PermissionCode[]`, no `IdentityPermissionCode[]`.
|
|
|
|
La existencia real de permisos se valida en Application con `IPermissionCatalog`.
|