Guía para Implementar JWT en Node.js con NestJS
¿Qué es un JSON Web Token?
El JSON Web Token (JWT) es un estándar abierto (RFC 7519) que define una forma compacta y autónoma de transmitir información de manera segura entre partes como un objeto JSON. Esta información se puede verificar y confiar en ella porque está firmada digitalmente. Los JWT pueden ser firmados usando un secreto (con el algoritmo HMAC) o un par de claves pública/privada utilizando RSA o ECDSA.
¿Cuándo deberías usar JSON Web Tokens?
- Autorización: Este es el escenario más común para usar JWT. Una vez que el usuario ha iniciado sesión, cada solicitud subsiguiente incluirá el JWT, lo que permite al usuario acceder a rutas, servicios y recursos permitidos por ese token. El inicio de sesión único (Single Sign-On) utiliza ampliamente JWT debido a su pequeño tamaño y su capacidad para usarse fácilmente entre diferentes dominios.
- Intercambio de información: Los JSON Web Tokens son una buena manera de transmitir información de manera segura entre partes. Dado que los JWT pueden estar firmados, por ejemplo, utilizando pares de claves pública/privada, puedes estar seguro de que los remitentes son quienes dicen ser. Además, como la firma se calcula utilizando el encabezado y el cuerpo, también puedes verificar que el contenido no haya sido alterado.
Configurando el Proyecto
npm i -g @nestjs/cli
nest new jwt-auth-demo
cd jwt-auth-demo
npm install @nestjs/jwt @nestjs/passport passport passport-jwt bcrypt
Definir el modelo del usuario:
// src/auth/user.model.ts
export class User {
id: number;
username: string;
password: string; // Store hashed passwords
}
Crear un servicio de usuario simple:
// src/auth/auth.service.ts
import { Injectable } from ‘@nestjs/common’;
import { User } from ‘./user.model’;
import * as bcrypt from ‘bcrypt’;
@Injectable()
export class AuthService {
private users: User[] = [];
async register(username: string, password: string): Promise<User> {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = { id: Date.now(), username, password:
hashedPassword };
this.users.push(newUser);
return newUser;
}
async validateUser(username: string, password: string): Promise<any> {
const user = this.users.find(user => user.username === username);
if (user && await bcrypt.compare(password, user.password)) {
return user;
}
return null;
}
}
Estrategia JWT
Decide el tipo de autenticación que deseas implementar. Las opciones comunes incluyen autenticación por nombre de usuario/contraseña, inicio de sesión con redes sociales (por ejemplo, utilizando OAuth) o autenticación basada en tokens (por ejemplo, JWT).
Configurar JWT:
// src/auth/auth.module.ts
import { Module } from ‘@nestjs/common’;
import { AuthService } from ‘./auth.service’;
import { JwtModule } from ‘@nestjs/jwt’;
import { PassportModule } from ‘@nestjs/passport’;
import { JwtStrategy } from ‘./jwt.strategy’;
@Module({
imports: [
PassportModule,
JwtModule.register({
secret: ‘secretKey’, // Use environment variable for production
signOptions: { expiresIn: ’60s’ },
}),
],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
Implementar la estrategia JWT:
// src/auth/jwt.strategy.ts
import { Injectable } from ‘@nestjs/common’;
import { PassportStrategy } from ‘@nestjs/passport’;
import { ExtractJwt, Strategy } from ‘passport-jwt’;
import { AuthService } from ‘./auth.service’;
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: ‘secretKey’,
});
}
async validate(payload: any) {
return this.authService.validateUser(payload.username, payload.sub);
}
}
Creación de EndPoint de autenticación:
// src/auth/auth.controller.ts
import { Controller, Post, Body, UseGuards } from ‘@nestjs/common’;
import { AuthService } from ‘./auth.service’;
import { JwtService } from ‘@nestjs/jwt’;
import { LocalAuthGuard } from ‘./local-auth.guard’;
@Controller(‘auth’)
export class AuthController {
constructor(
private readonly authService: AuthService,
private jwtService: JwtService,
) {}
@Post(‘register’)
async register(@Body() body: { username: string; password: string }) {
return this.authService.register(body.username, body.password);
}
@UseGuards(LocalAuthGuard)
@Post(‘login’)
async login(@Body() body: { username: string; password: string }) {
const user = await this.authService.validateUser(body.username, body.password);
const payload = { username: user.username, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
};
}
}
Implementar LocalAuthGuard
// src/auth/local-auth.guard.ts
import { Injectable } from ‘@nestjs/common’;
import { AuthGuard } from ‘@nestjs/passport’;
@Injectable()
export class LocalAuthGuard extends AuthGuard(‘local’) {}
Rutas protegidas:
Usa el decorador @UseGuards para proteger rutas específicas:
import { Controller, Get, UseGuards } from ‘@nestjs/common’;
import { JwtAuthGuard } from ‘./jwt-auth.guard’;
@Controller(‘protected’)
export class ProtectedController {
@UseGuards(JwtAuthGuard)
@Get()
getProtectedData() {
return { message: ‘This is protected data’ };
}
}
Conclusión:
Este artículo cubrió la implementación de la autenticación JWT en una aplicación de Node.js utilizando NestJS. Se destacaron los beneficios clave de JWT para la autenticación de usuarios sin estado y escalable, junto con la configuración de un módulo de autenticación, la implementación de una estrategia JWT y la creación de puntos finales seguros para el registro y el inicio de sesión de usuarios. Para mejorar aún más la seguridad de la aplicación, es recomendable explorar las mejores prácticas relacionadas con la expiración de tokens y los tokens de actualización.
Noticias relacionadas
-
- BI
¿Cómo aprovechar las tecnologías de seguridad en la nube para proteger los datos de tu empresa?
Publicado por GRUPO EBIM 19 Abr 23 -
- Desarrollo
- SAP
¿Cómo crear Excel con objetos OLE2 desde SAP?
Publicado por GRUPO EBIM 08 Jul 24 -
- SAP
- Desarrollo
¿Cómo crear tipos de imputación para documentos de compras en SAP?
Publicado por GRUPO EBIM 01 Jul 24