Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Carrera
Programador
full-stack
AUTHENTICATION
CFS
AUTHENTICATION
La autenticación es parte esencial en la mayoría de las
aplicaciones. Hay varias estrategias que podemos emplear.
*Luego lo ampliaremos emitiendo un JWT. Finalmente, crearemos una ruta protegida que compruebe si la
petición contiene un JWT válido.
CFS
@Injectable()
export class UserService {
async findUser(email: string): Promise<User> {
const res = await fetch(BASE_URL);
if (!res.ok)
throw new HttpException(
'Internal Server Error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
const allUsers = await res.json();
const user = allUsers.find((usr: User) => usr.email === email);
return user;
}
}
CFS
El servicio que acabamos de crear se vincula con las entidades
“usuario”. Busca una de acuerdo a un email y, si la encuentra,
la retorna.
@Module({
providers: [UserService],
exports: [UserService],
})
export class UserModule {}
CFS
Login endpoint
@Injectable()
export class AuthService {
constructor(private userService: UserService) {}
async login(email: string, pass: string): Promise<any> {
const user = await this.userService.findUser(email);
if (user?.password !== pass) {
throw new UnauthorizedException();
}
const { password, ...rest } = user;
return rest;
}
}
CFS
Login endpoint
@Module({
imports: [UserModule],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}
CFS
Login endpoint
Con las piezas en su lugar, solo resta abrir AuthController y agregar un método login,
que va a ser llamado por el cliente para autenticar un usuario.
No olvidemos el DTO, ahora que ya sabemos usarlos para validar las peticiones
auth/login.dto.ts
import { IsEmail, IsString, MaxLength, MinLength } from
'class-validator';
export class LoginDto {
@IsEmail()
email: string;
@MinLength(6)
@MaxLength(15)
@IsString()
password: string;
}
CFS
Login endpoint
Y por último, nuestro controlador:
auth/auth.controller.ts
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@HttpCode(HttpStatus.OK)
@Post('login')
login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto.email, loginDto.password);
}
}
CFS
npm install
@nestjs/jwt
* No hay traducción literal. En este contexto significa “vale al portador”, es decir, un objeto que
trae el portador y le garantiza acceso a un recurso.
CFS
JWT Token
Vamos a mantener nuestros servicios modularizados y
limpios, para lo cual nos conviene generar el token JWT
en AuthService.
@Injectable()
export class AuthService {
constructor(
private userService: UserService,
private jwtService: JwtService,
) {}
Estamos usando la librería @nestjs/jwt, que prove una función signAsync() para
generar nuestros JWT a partir de un subconjunto de propiedades del objeto user (el
payload).
Asimismo, la propiedad sub representa el id del usuario. Le ponemos sub para ser
consistentes con el estándar que propone JWT, pero también puede llamarse con
cualquier nombre… aunque la sabiduría popular recomienda:
auth/constants.ts
/*
Esto es solo para fines educativos. La clave no debe estar
expuesta. Debe ir fuera del código. ¿Por qué?.
Porque con ella se pueden crear y verificar tokens.
Es habitual almacenarla en variables de entorno o en una
base de datos segura.
*/
CFS auth/auth.module.ts
@Module({
imports: [
UserModule,
JwtModule.register({
global: true,
secret: jwtConstants.secret,
signOptions: { expiresIn: '1h' },
}),
],
providers: [AuthService],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {}
CFS
Ahora, si hacemos una petición de tipo POST al endpoint /auth/login y el par
email / contraseña coincide con los datos almacenados en un registro de
nuestra base de datos, el servidor nos entrega en su respuesta un JWT.
Authentication Guard
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { jwtConstants } from './constants';
import { Request } from 'express';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
@UseGuards(AuthGuard)
@Delete(':id')
CFS