Este diagrama mostra, de forma clara e enxuta, todo o fluxo de autenticação do sistema:
- Registro de novos usuários com senha criptografada
- Login por credenciais e via OAuth2 (GitHub/Google)
- Recuperação de senha (esqueci senha + redefinição) sem expor existência de conta
- Logout via blacklist de token
- Acesso a rotas protegidas validando JWT e blacklist
--- config: theme: redux-dark-color --- sequenceDiagram autonumber participant FE as Front-end participant API as REST API participant DB as MySQL participant REDIS as Redis (Blacklist) participant SES as Serviço de Email participant OAUTH as OAuth2 Provider %% 1) REGISTRO rect rgba(0, 0, 255, 0.1) FE->>API: POST /auth/register {email, senha, confirmação, nome, termos} API->>DB: cria usuário com senha criptografada DB-->>API: usuário criado (id) API-->API: gera JWT + Refresh API-->>FE: 201 Created {access, refresh} end %% 2) LOGIN POR CREDENCIAIS rect rgba(0, 128, 0, 0.1) FE->>API: POST /auth/login {email, senha} API->>DB: busca usuário por email e compare hash alt credenciais válidas API-->API: gera JWT + Refresh API-->>FE: 200 OK {access, refresh} else inválido API-->>FE: 401 Unauthorized {"Email ou senha inválidos"} end end %% 3) LOGIN VIA OAUTH2 rect rgba(0, 128, 128, 0.1) FE->>OAUTH: redirect para login externo OAUTH-->>FE: Callback OAuth2 com ccódigo FE->>API: GET /auth/oauth2/success?code=… API-->API: troca código por userInfo API->>DB: busca ou cria usuário via provider API-->API: gera JWT API-->>FE: 200 OK {access} end %% 4) ESQUECI SENHA → RESET rect rgba(255, 165, 0, 0.1) FE->>API: POST /auth/forgot-password?email=… API->>DB: tenta buscar usuário por email alt email cadastrado API-->API: cria token (UUID + hash) e persiste API-->API: monta link de reset API->>SES: envia email com link else não cadastrado Note right of API: ignora e retorna mesma resposta end API-->>FE: 200 OK {"Confira seu email para instruções"} end rect rgba(255, 140, 0, 0.1) FE->>API: POST /auth/reset-password {key, token, novaSenha} API->>DB: busca token de reset por key alt token válido e não expirado API-->API: atualiza senha (hash) e marca token usado API-->>FE: 200 OK {"Senha redefinida com sucesso"} else inválido ou expirado API-->>FE: 400 Bad Request {"Token inválido ou expirado"} end end %% 5) LOGOUT rect rgba(220, 20, 60, 0.1) FE->>API: POST /auth/logout (Bearer JWT) API-->API: extrai jti + exp do token API->>REDIS: adiciona jti na blacklist até expirar REDIS-->>API: OK API-->>FE: 200 OK {"Logout realizado"} end %% 6) ACESSO A RECURSOS PROTEGIDOS rect rgba(128, 0, 128, 0.1) FE->>API: GET /api/recurso (Bearer JWT) API-->API: JwtAuthFilter intercepta API->>REDIS: verifica se jti está blacklist alt token válido e não blacklist API-->>FE: 200 OK {dados…} else inválido ou blacklist API-->>FE: 401 Unauthorized {"Token inválido ou expirado"} end end Este diagrama ilustra o fluxo completo de comunicação fim-a-fim criptografada implementado na nossa API usando o protocolo Signal:
- Mostra como o cliente gera e publica chaves na primeira inicialização (ou quando o storage local é perdido).
- Descreve o handshake de sessão entre usuários, com fetch seguro de bundles.
- Explica o envio de mensagens cifradas via WebSocket, totalmente opacas ao servidor.
- Detalha como o backend monitora pre-keys e signedPreKeys, enviando alertas automáticos para reposição ou rotação.
- Representa a segurança baseada em IndexedDB local com trust-on-first-use.
--- config: theme: redux-dark-color --- sequenceDiagram autonumber participant FE_A as Frontend A participant SC_A as SignalClient A participant WS as WebSocket Broker participant API as REST API participant FE_B as Frontend B participant SC_B as SignalClient B rect rgba(0, 0, 255, 0.1) FE_A->>SC_A: bootstrap() alt Primeiro login OU IndexedDB limpo/perdido SC_A->>API: POST /signal/keys/save API-->>SC_A: 201 Created else Já tem chaves locais SC_A-->SC_A: Load keys from IndexedDB end end rect rgba(0, 100, 0, 0.1) FE_A->>SC_A: ensureSession(B) SC_A->>API: GET /signal/keys/fetch/{B} API-->>SC_A: {identity_B, SPK_B, PK₁} SC_A-->SC_A: SessionBuilder.processPreKey() end rect rgba(128, 0, 128, 0.1) FE_A->>SC_A: encrypt("Olá") SC_A->>WS: SEND /chat (ciphertext, type=WHISPER) WS->>FE_B: MESSAGE (ciphertext) FE_B->>SC_B: decrypt() SC_B-->FE_B: "Olá" end rect rgba(255, 165, 0, 0.1) Note over API: Monitor de PreKeys API->>WS: toUser(B) {type: LOW_PREKEY, remaining:18} WS->>FE_B: evento LOW_PREKEY FE_B->>SC_B: replenishBundle() (+100 PK) SC_B->>API: POST /signal/keys/save (novos PKs) API-->>SC_B: 201 Created end rect rgba(220, 20, 60, 0.1) Note over API: Scheduler detecta SPK expirada API->>WS: toUser(B) {type: SPK_EXPIRED} WS->>FE_B: evento SPK_EXPIRED FE_B->>SC_B: rotateSignedPreKey() SC_B->>API: POST /signal/keys/rotate-spk (nova SPK₁) API-->>SC_B: 200 OK end Note over FE_A,FE_B: 🛡️ Próxima mensagem usa SPK₁ de B | MySQL | Hibernate | Spring Boot | Java | Redis | JWT | WebSocket |
| 🔖 8.1.0 | 🔖 6.3 | 🔖 3.3.2 | 🔖 17 | 🔖 7.4.2 | 🔖 0.12.6 | 🔖 3.4.2 |
| IntelliJ IDEA | DataGrip | Postman | Docker | Maven | GitHub Actions |
| 🔖 2024.3.2 | 🔖 2024.3 | 🔖 11.32.1 | 🔖 27.5.1 | 🔖 3.9.6 | 🔖 - |
| AWS S3 | AWS SES | AWS CloudWatch |
| Swagger | Cucumber | JUnit | ArchUnit | TestContainers |
| 🔖 2.8.5 | 🔖 7.21.1 | 🔖 5 | 🔖 1.4.0 | 🔖 1.20.4 |