A Auth API é responsável pela autenticação de usuários e geração de tokens JWT utilizados por todos os demais microserviços do domínio store. Ela valida credenciais, emite tokens de acesso e garante a integridade das comunicações dentro da arquitetura de microsserviços.
Trusted layer e segurança
O acesso à Auth API é realizado via Gateway. Após o login, o JWT é retornado ao cliente e utilizado nas demais requisições aos serviços protegidos (account, order, product, exchange).
Visão geral
Service (auth-service): Implementado em Spring Boot (Java). Expõe endpoints públicos para autenticação e registro de usuários. Integra-se com o account-service para validação de usuários e gera tokens JWT assinados com a chave definida em JWT_SECRET_KEY.
Fluxo de autenticação
O cliente envia email e password para /auth/login.
O Auth API valida as credenciais no account-service.
Em caso de sucesso, é gerado e retornado o token JWT.
O gateway-service utiliza esse token para validar requisições futuras e injetar o id-account nos headers.
classDiagram
namespace auth {
class AuthController {
+register(RegisterIn RegisterIn): TokenOut
+login(LoginIn loginIn): TokenOut
}
class RegisterIn {
-String name
-String email
-String password
}
class LoginIn {
-String name
-String email
}
class TokenOut {
-String token
}
class SolveOut {
-String idAccount
}
}
namespace auth-service {
class AuthResource {
+register(RegisterIn RegisterIn) TokenOut
+login(LoginIn loginIn) TokenOut
}
class AuthService {
+register(Register) Regiter
+login(LoginIn loginIn) String
}
class Register {
-String id
-String name
-String email
-String password
}
}
<<Interface>> AuthController
AuthController ..> RegisterIn
AuthController ..> LoginIn
AuthController ..> TokenOut
AuthController <|-- AuthResource
AuthResource *-- AuthService
AuthService ..> Register
Estrutura da requisição
flowchart LR
subgraph api [Trusted Layer]
direction TB
gateway --> account
gateway --> others
gateway e4@==> auth:::red
auth e2@==> account
account --> db@{ shape: cyl, label: "Database" }
others --> db
end
internet e1@==>|request| gateway:::orange
e1@{ animate: true }
e2@{ animate: true }
e4@{ animate: true }
classDef red fill:#fcc
classDef orange fill:#FCBE3E
packagestore.auth;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.stereotype.Service;importorg.springframework.web.server.ResponseStatusException;importstore.account.AccountController;importstore.account.AccountIn;importstore.account.AccountOut;@ServicepublicclassAuthService{privateLoggerlogger=LoggerFactory.getLogger(AuthService.class);@AutowiredprivateAccountControlleraccountController;@AutowiredprivateJwtServicejwtService;publicStringregister(Stringname,Stringemail,Stringpassword){logger.debug(String.format("registrando uma conta: [%s] for [%s]",name,email));// Salvar no servico de AccountAccountOutaccount=accountController.create(AccountIn.builder().name(name).email(email).password(password).build()).getBody();// Gera um tokenStringjwtString=jwtService.generate(account);// Retorna o tokenreturnjwtString;}publicStringlogin(Stringemail,Stringpassword){logger.debug(String.format("required login for %s:%s",email,password));// Verify credentialsResponseEntity<AccountOut>response=accountController.findByEmailAndPassword(AccountIn.builder().email(email).password(password).build());if(!response.hasBody()){logger.debug(String.format("user not found"));thrownewResponseStatusException(HttpStatus.UNAUTHORIZED);}AccountOutaccount=response.getBody();logger.debug(String.format("found user",account));// generate tokenreturnjwtService.generate(account);}publicAccountOutsolve(Stringjwt){returnAccountOut.builder().id(jwtService.getId(jwt)).build();}}
packagestore.auth;importjava.util.Date;importjava.util.Map;importjavax.crypto.SecretKey;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.http.HttpStatus;importorg.springframework.stereotype.Service;importorg.springframework.web.server.ResponseStatusException;importio.jsonwebtoken.Claims;importio.jsonwebtoken.JwtParser;importio.jsonwebtoken.Jwts;importio.jsonwebtoken.io.Decoders;importio.jsonwebtoken.security.Keys;importstore.account.AccountOut;@ServicepublicclassJwtService{@Value("${store.jwt.secretKey}")privateStringsecretKey;publicStringgenerate(AccountOutaccount){Datenow=newDate();Stringjwt=Jwts.builder().header().and().id(account.id()).issuer("Insper::PMA").claims(Map.of("email",account.email())).signWith(getKey()).subject(account.name()).notBefore(now).expiration(newDate(now.getTime()+1000*60*120))// em milisegundos.compact();returnjwt;}publicStringgetId(Stringjwt){// constroe o parserJwtParserparser=Jwts.parser().verifyWith(getKey()).build();// recupero os atributosClaimsclaims=parser.parseSignedClaims(jwt).getPayload();Datenow=newDate();if(claims.getNotBefore().after(now)){thrownewResponseStatusException(HttpStatus.UNAUTHORIZED,"Token is not valid yet!");}if(claims.getExpiration().before(now)){thrownewResponseStatusException(HttpStatus.UNAUTHORIZED,"Token is expired!");}returnclaims.getId();}privateSecretKeygetKey(){returnKeys.hmacShaKeyFor(Decoders.BASE64.decode(secretKey));}}