A Ton Products API implementa um sistema de autenticação robusto baseado em JWT (JSON Web Tokens) com criptografia bcrypt para senhas.
┌────────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Auth Guard │ │ Auth Service │ │ Encryption Svc │
│ │ │ │ │ │
│ • JWT Validation │────│ • Login Logic │────│ • bcrypt Hash │
│ • Route Protection │ │ • Token Gen │ │ • Password Cmp │
│ • User Context │ │ • User Validation│ │ • Salt Generation│
└────────────────────┘ └─────────────────┘ └──────────────────┘
│ │ │
└──────────────────┬────────────────────────────┘
│
┌─────────────────┐
│ User Service │
│ │
│ • User CRUD │
│ • Profile Mgmt │
│ • Email Search │
└─────────────────┘
sequenceDiagram
participant C as Client
participant AC as AuthController
participant AS as AuthService
participant ES as EncryptionService
participant US as UserService
participant DB as Database
C->>AC: POST /auth/signup
AC->>AS: signup(userData)
AS->>US: findByEmail(email)
US-->>AS: null (user not exists)
AS->>ES: hashPassword(password)
ES-->>AS: hashedPassword
AS->>US: create(userWithHashedPassword)
US->>DB: save user
DB-->>US: saved user
US-->>AS: created user
AS-->>AC: success response
AC-->>C: 201 Created + user data
sequenceDiagram
participant C as Client
participant AC as AuthController
participant AS as AuthService
participant ES as EncryptionService
participant JS as JwtService
C->>AC: POST /auth/login
AC->>AS: login(credentials)
AS->>AS: validateUser(email, password)
AS->>ES: comparePassword(password, hash)
ES-->>AS: true/false
AS->>JS: sign(payload)
JS-->>AS: jwt token
AS-->>AC: token + user data
AC-->>C: 200 OK + access token
sequenceDiagram
participant C as Client
participant AG as AuthGuard
participant JS as JwtService
participant PC as ProductsController
C->>AG: GET /products + Bearer token
AG->>JS: verify(token)
JS-->>AG: decoded payload
AG->>AG: extract user info
AG->>PC: proceed with user context
PC-->>C: protected resource
Serviço centralizado para operações criptográficas:
@Injectable()
export class EncryptionService {
async hashPassword(password: string): Promise<string> {
const saltRounds = parseInt(ENV.SALT_ROUNDS);
return await bcrypt.hash(password, saltRounds);
}
async comparePassword(password: string, hash: string): Promise<boolean> {
return await bcrypt.compare(password, hash);
}
async generateSalt(rounds?: number): Promise<string> {
return await bcrypt.genSalt(rounds || parseInt(ENV.SALT_ROUNDS));
}
}
Características:
Estratégia de validação de tokens JWT:
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: ENV.JWT_SECRET,
});
}
async validate(payload: any) {
return {
userId: payload.sub,
email: payload.email
};
}
}
Guard para proteção de rotas:
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
handleRequest(err, user, info) {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}
# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-here
JWT_EXPIRES_IN=7d
# Encryption Configuration
SALT_ROUNDS=12
JwtModule.register({
secret: ENV.JWT_SECRET,
signOptions: {
expiresIn: '7d',
issuer: 'ton-products-api',
audience: 'ton-products-client'
},
})
export class SignupDto {
@IsString()
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
@IsString()
@MinLength(6)
password: string;
}
export class LoginDto {
@IsEmail()
email: string;
@IsString()
@IsNotEmpty()
password: string;
}
curl -X POST http://localhost:3000/auth/signup \
-H "Content-Type: application/json" \
-d '{
"name": "Test User",
"email": "test@example.com",
"password": "test123456"
}'
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "test123456"
}'
curl -X GET http://localhost:3000/products \
-H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"