add jwt guard and another EP to return information
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import {
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
ForbiddenException,
|
||||
} from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {
|
||||
handleRequest(err: any, user: any, info: any, context: ExecutionContext) {
|
||||
if (err || !user) {
|
||||
throw new ForbiddenException('Acceso denegado: token inválido o ausente');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Injectable, ForbiddenException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
export interface JwtPayload {
|
||||
id: string;
|
||||
usuario: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
constructor(private configService: ConfigService) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: configService.get<string>('JWT_SECRET')!,
|
||||
});
|
||||
}
|
||||
|
||||
async validate(payload: JwtPayload) {
|
||||
if (!payload || !payload.id || !payload.usuario) {
|
||||
throw new ForbiddenException('Token inválido o corrupto');
|
||||
}
|
||||
return { id: payload.id, usuario: payload.usuario };
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Controller, Get, UseGuards, Req, Res } from '@nestjs/common';
|
||||
import type { Response } from 'express';
|
||||
import { PersonaService } from './persona.service';
|
||||
import { GoogleAuthGuard } from './google-auth.guard';
|
||||
import { JwtAuthGuard } from './jwt.guard';
|
||||
|
||||
@Controller('persona')
|
||||
export class PersonaController {
|
||||
@@ -12,14 +13,10 @@ export class PersonaController {
|
||||
return this.personaService.findAll();
|
||||
}
|
||||
|
||||
// Redirige a Google
|
||||
@Get('google')
|
||||
@UseGuards(GoogleAuthGuard)
|
||||
async googleLogin() {
|
||||
// NestJS + Passport se encarga de redirigir a Google
|
||||
}
|
||||
async googleLogin() {}
|
||||
|
||||
// Callback después de autenticación en Google
|
||||
@Get('google/callback')
|
||||
@UseGuards(GoogleAuthGuard)
|
||||
async googleCallback(@Req() req, @Res() res: Response) {
|
||||
@@ -32,11 +29,23 @@ export class PersonaController {
|
||||
// Generar JWT con los datos de la persona
|
||||
const jwt = await this.personaService.generateJwt(persona);
|
||||
|
||||
return res.status(200).json({
|
||||
return res.redirect(
|
||||
`${process.env.FRONTEND_URL}/oauth-callback?token=${jwt.access_token}`,
|
||||
);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('me')
|
||||
async getMe(@Req() req) {
|
||||
const idPersona = req.user.idPersona;
|
||||
|
||||
const persona = await this.personaService.findById(idPersona);
|
||||
|
||||
return {
|
||||
error: false,
|
||||
msj: `Bienvenido ${persona.nombre} ${persona.apellidoP} ${persona.apellidoM}`,
|
||||
data: {
|
||||
token: jwt.access_token,
|
||||
token: req.headers.authorization.split(' ')[1], // token que envió el cliente
|
||||
userId: persona.idPersona,
|
||||
nombre: persona.nombre,
|
||||
apellidoP: persona.apellidoP,
|
||||
@@ -48,6 +57,6 @@ export class PersonaController {
|
||||
primerLogin: persona.primerLogin,
|
||||
cambioPassword: persona.cambioPasswordReq,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,31 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { PersonaService } from './persona.service';
|
||||
import { PersonaController } from './persona.controller';
|
||||
import { GoogleStrategy } from './google.strategy';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Persona } from './entities/persona.entity';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { GoogleStrategy } from './google.strategy';
|
||||
import { JwtStrategy } from './jwt.strategy';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Persona]),
|
||||
PassportModule,
|
||||
PassportModule.register({ defaultStrategy: 'jwt' }),
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (cs: ConfigService) => {
|
||||
const secret = cs.get<string>('JWT_SECRET');
|
||||
if (!secret) {
|
||||
throw new Error('JWT_SECRET no está definido');
|
||||
}
|
||||
|
||||
// Se obtiene el valor de JWT_EXPIRES_IN en segundos
|
||||
const expiresInStr = cs.get<string>('JWT_EXPIRES_IN') || '3600';
|
||||
const expiresIn = parseInt(expiresInStr, 10); // convertir a número
|
||||
if (isNaN(expiresIn)) {
|
||||
throw new Error(
|
||||
'JWT_EXPIRES_IN debe ser un número válido en segundos',
|
||||
);
|
||||
}
|
||||
|
||||
useFactory: async (configService: ConfigService) => {
|
||||
return {
|
||||
secret,
|
||||
signOptions: { expiresIn }, // aquí ya es un número
|
||||
global: true,
|
||||
secret: configService.get<string>('JWT_SECRET'),
|
||||
signOptions: { expiresIn: '1h' },
|
||||
};
|
||||
},
|
||||
}),
|
||||
],
|
||||
controllers: [PersonaController],
|
||||
controllers: [PersonaController, JwtStrategy],
|
||||
providers: [PersonaService, GoogleStrategy],
|
||||
})
|
||||
export class PersonaModule {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { Repository } from 'typeorm';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
@@ -31,6 +31,15 @@ export class PersonaService {
|
||||
return this.personaRepository.save(persona);
|
||||
}
|
||||
|
||||
async findById(idPersona): Promise<Persona> {
|
||||
const user = await this.personaRepository.findOne({ where: { idPersona } });
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException('user not found');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
async generateJwt(user: Persona) {
|
||||
const payload = {
|
||||
userType: 'usuario',
|
||||
@@ -42,7 +51,6 @@ export class PersonaService {
|
||||
};
|
||||
}
|
||||
|
||||
// Opción: validateOrCreateGoogleUser para usar en GoogleStrategy
|
||||
async validateOrCreateGoogleUser(data: { email: string; apellido: string }) {
|
||||
let persona = await this.findByEmail(data.email);
|
||||
|
||||
@@ -52,7 +60,6 @@ export class PersonaService {
|
||||
const apellidoM = apellidoArray[1] || '';
|
||||
const nombre = apellidoArray.slice(2).join(' ') || '';
|
||||
|
||||
// Número identificador del correo
|
||||
const numeroIdentificar = data.email.split('@')[0];
|
||||
|
||||
const password = await passwordRand(12);
|
||||
@@ -79,4 +86,9 @@ export class PersonaService {
|
||||
|
||||
return persona;
|
||||
}
|
||||
|
||||
saldo(idPersona) {
|
||||
this.personaRepository.findOne({ where: { idPersona } });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user