Camadas da Arquitetura - ecosif-auth
Visão Geral das Camadas
O projeto ecosif-auth segue a arquitetura em camadas do Spring Boot, com separação clara de responsabilidades.
Estrutura de Camadas
┌─────────────────────────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Controllers │ │
│ │ - AuthController │ │
│ │ - DockerLogsController │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Filters │ │
│ │ - TokenAuthenticationFilter │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ BUSINESS LAYER │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Services │ │
│ │ - UserService / UserServiceImpl │ │
│ │ - LocalUserDetailService │ │
│ │ - ExternalAuthenticationService │ │
│ │ - io.ecosif.security.jwt.TokenProvider (starter) │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ DTOs │ │
│ │ - LoginRequest │ │
│ │ - LoginRequestAzure │ │
│ │ - JwtAuthenticationResponse │ │
│ │ - UserInfo │ │
│ │ - UserCreateAzureDTO │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DATA ACCESS LAYER │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Repositories │ │
│ │ - UserRepository │ │
│ │ - RoleRepository │ │
│ │ - BusinessAccountRepository │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Entities │ │
│ │ - User │ │
│ │ - Role │ │
│ │ - BusinessAccount │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ INFRASTRUCTURE LAYER │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Database (PostgreSQL) │ │
│ │ - Schema: public │ │
│ │ - Tables: gr_user, roles, businessaccount │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Configuration │ │
│ │ - WebSecurityConfig │ │
│ │ - PasswordEncoderConfig │ │
│ │ - OpenApiConfig │ │
│ │ - AppProperties │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1. Presentation Layer (Camada de Apresentação)
Controllers
Responsáveis por receber requisições HTTP, validar entradas e retornar respostas.
AuthController
- Responsabilidade: Gerenciar autenticação de usuários
- Endpoints:
POST /api/auth/signin: Autenticação localPOST /api/auth/external-login: Login Microsoft/Google (id_token)- Validações: Validação de DTOs usando Bean Validation
- Tratamento de Erros: Utiliza GlobalExceptionHandler
DockerLogsController
- Responsabilidade: Endpoints administrativos para visualização de logs
- Endpoints:
GET /api/admin/docker-logs: Obter logs de um containerGET /api/admin/docker-logs/services: Listar serviços disponíveis- Segurança: Requer autenticação JWT
Filters
TokenAuthenticationFilter
- Responsabilidade: Interceptar requisições e validar tokens JWT
- Fluxo:
1. Extrai token do header
Authorization2. Valida token usandoTokenProvider3. Carrega usuário do banco de dados 4. Define contexto de segurança do Spring
2. Business Layer (Camada de Negócio)
Services
Implementam a lógica de negócio do sistema.
UserService / UserServiceImpl
- Responsabilidade: Gerenciar operações de usuários
- Métodos principais:
findUserByUsername(String email): Buscar usuário por usernamefindUserById(Long id): Buscar usuário por IDsave(User user): Salvar ou atualizar usuário- Transações: Métodos marcados com
@Transactional
LocalUserDetailService
- Responsabilidade: Integração com Spring Security
- Implementa:
UserDetailsService - Método principal:
loadUserByUsername(String username) - Retorna:
LocalUser(implementação deUserDetails)
TokenProvider (starter)
- Pacote:
io.ecosif.security.jwt.TokenProvider(ecosif-spring-boot-starter-security) createToken(LocalUser userPrincipal): Criar novo token JWTvalidateToken(String authToken): Validar token JWTgetUserIdFromToken(String token): Extrair username do token- Algoritmo: HS256 (HMAC SHA-256)
DTOs (Data Transfer Objects)
Objetos para transferência de dados entre camadas.
LoginRequest
- Uso: Requisição de autenticação local
- Campos:
username(String, obrigatório)password(String, obrigatório)azure(Boolean) — legado; setrueretorna 400
ExternalLoginRequest
- Uso:
POST /api/auth/external-login - Campos:
provider,token,tokenType
LoginRequestAzure (removido)
username(String, obrigatório)userCreate(UserCreateAzureDTO, opcional)
JwtAuthenticationResponse
- Uso: Resposta de autenticação bem-sucedida
- Campos:
accessToken(String): Token JWTuser(UserInfo): Informações do usuáriotenantName(String): Nome do tenant
UserInfo
- Uso: Informações do usuário autenticado
- Campos:
id(String): ID do usuáriodisplayName(String): Nome completoemail(String): Emailroles(List): Lista de roles/perfis tenant(String): Tenant/empresa
3. Data Access Layer (Camada de Acesso a Dados)
Repositories
Interfaces Spring Data JPA para acesso a dados.
UserRepository
- Estende:
JpaRepository<User, Long> - Métodos customizados:
findByUsername(String username): Buscar por usernameexistsByUsername(String email): Verificar existência por username
RoleRepository
- Estende:
JpaRepository<Role, Long> - Uso: Gerenciamento de roles (atualmente não muito utilizado)
BusinessAccountRepository
- Estende:
JpaRepository<BusinessAccount, Long> - Uso: Gerenciamento de contas de negócio (tenants)
Entities
Entidades JPA que representam tabelas do banco de dados.
User
- Tabela:
gr_user - Campos principais:
id(Long): ID primárioname(String): Nome completousername(String): Username/email (único)password(String): Senha criptografada (BCrypt)active(boolean): Status ativo/inativorole(String): Role/perfil do usuáriotenant(String): Tenant/empresaexpiryDate(Date): Data de expiração
Role
- Tabela:
roles - Campos principais:
id(Long): ID primárioname(String): Nome da role
BusinessAccount
- Tabela:
businessaccount - Campos principais:
id(Long): ID primárioname(String): Nome da conta (único)
4. Infrastructure Layer (Camada de Infraestrutura)
Database
PostgreSQL
- Versão: 13+ (recomendado 15)
- Schema:
public - Tabelas principais:
gr_user: Usuários do sistemaroles: Roles/perfis (não muito utilizado)businessaccount: Contas de negócio (tenants)
Flyway
- Responsabilidade: Gerenciamento de migrações de banco de dados
- Localização:
src/main/resources/db/migration/ - Convenção de nomenclatura:
V{version}__{description}.sql
Configuration
WebSecurityConfig
- Responsabilidade: Configuração de segurança Spring Security
- Recursos configurados:
- CORS
- CSRF (desabilitado para API REST)
- Autenticação JWT
- OAuth2 (opcional)
- Autorização de endpoints
PasswordEncoderConfig
- Responsabilidade: Configuração do encoder de senhas
- Algoritmo: BCrypt
- Bean:
PasswordEncoder
OpenApiConfig
- Responsabilidade: Configuração do Swagger/OpenAPI
- Biblioteca: SpringDoc OpenAPI 3.0
- Endpoints:
- Swagger UI:
/swagger-ui.html - OpenAPI JSON:
/v3/api-docs
AppProperties
- Responsabilidade: Propriedades customizadas da aplicação
- Propriedades:
app.auth.tokenSecret: Chave secreta JWTapp.auth.tokenExpirationMsec: Tempo de expiração do token
Fluxo de Dados entre Camadas
Exemplo: Processo de Autenticação
1. Cliente → Controller
POST /api/auth/signin
{ username, password }
2. Controller → Service
userService.findUserByUsername(username)
3. Service → Repository
userRepository.findByUsername(username)
4. Repository → Database
SELECT * FROM gr_user WHERE username = ?
5. Database → Repository
User entity
6. Repository → Service
User entity
7. Service → Controller
User entity
8. Controller → AuthenticationManager
authenticate(username, password)
9. AuthenticationManager → LocalUserDetailService
loadUserByUsername(username)
10. LocalUserDetailService → Repository → Database
(busca usuário novamente)
11. AuthenticationManager → Controller
Authentication (com LocalUser)
12. Controller → TokenProvider
createToken(localUser)
13. TokenProvider → Controller
JWT Token
14. Controller → Cliente
200 OK + JWT Token + UserInfo
Princípios de Design
Separation of Concerns (Separação de Responsabilidades)
- Cada camada tem responsabilidades claras e bem definidas
- Controllers não contêm lógica de negócio
- Services não conhecem detalhes de apresentação
- Repositories são apenas interfaces de acesso a dados
Dependency Inversion (Inversão de Dependências)
- Camadas superiores dependem de abstrações (interfaces)
- Implementações estão nas camadas inferiores
- Facilita testes e manutenção
Single Responsibility (Responsabilidade Única)
- Cada classe tem uma única responsabilidade
- Facilita compreensão e manutenção do código
Don't Repeat Yourself (DRY)
- Lógica comum é extraída para serviços compartilhados
- Validações reutilizáveis são definidas em DTOs
Testabilidade
A arquitetura em camadas facilita testes unitários e de integração:
- Controllers: Testáveis com
@WebMvcTest - Services: Testáveis com mocks de repositories
- Repositories: Testáveis com
@DataJpaTeste banco em memória - TokenProvider: Testável de forma isolada