create simpel login

This commit is contained in:
TheManus88
2024-09-11 22:35:57 -06:00
parent 6c59c341e7
commit ca79113b62
14 changed files with 373 additions and 14 deletions
+3 -1
View File
@@ -3,4 +3,6 @@ DB_PORT: 3306
DB_USERNAME: 'root'
DB_PASSWORD: 'Test2024'
DB_NAME: 'pdi'
DB_SYNCHRONIZE: true
DB_SYNCHRONIZE: true
JWT_SECRET: e7b217737e39bb2b34701ca23f513e48269565073a4b5d6b5d5c057794d90463
JWT_EXPIRES: '1h'
+156 -3
View File
@@ -9,11 +9,14 @@
"version": "0.0.1",
"license": "UNLICENSED",
"dependencies": {
"@nestjs/class-validator": "^0.13.4",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/typeorm": "^10.0.2",
"class-transformer": "^0.5.1",
"dotenv": "^16.4.5",
"mysql2": "^3.11.1",
"reflect-metadata": "^0.1.13",
@@ -1664,6 +1667,16 @@
"node": ">=8"
}
},
"node_modules/@nestjs/class-validator": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/@nestjs/class-validator/-/class-validator-0.13.4.tgz",
"integrity": "sha512-/mqZL36LJ5uV5WDhi87Cd52IssuO+SStaOr2+6sBsvCCGUWkoJes4Wwzmm3m/gdHH+tsNxX60sVSzYcU6hAy9Q==",
"license": "MIT",
"dependencies": {
"libphonenumber-js": "^1.9.43",
"validator": "^13.7.0"
}
},
"node_modules/@nestjs/cli": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.4.5.tgz",
@@ -1806,6 +1819,19 @@
}
}
},
"node_modules/@nestjs/jwt": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-10.2.0.tgz",
"integrity": "sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==",
"license": "MIT",
"dependencies": {
"@types/jsonwebtoken": "9.0.5",
"jsonwebtoken": "9.0.2"
},
"peerDependencies": {
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/@nestjs/platform-express": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.1.tgz",
@@ -2203,6 +2229,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz",
"integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/methods": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz",
@@ -2221,7 +2256,6 @@
"version": "20.16.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz",
"integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
@@ -3304,6 +3338,12 @@
"ieee754": "^1.1.13"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -3481,6 +3521,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
"license": "MIT"
},
"node_modules/cli-cursor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -4120,6 +4166,15 @@
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"license": "MIT"
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -6625,6 +6680,49 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"license": "MIT",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"license": "MIT",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -6669,6 +6767,12 @@
"node": ">= 0.8.0"
}
},
"node_modules/libphonenumber-js": {
"version": "1.11.8",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.8.tgz",
"integrity": "sha512-0fv/YKpJBAgXKy0kaS3fnqoUVN8901vUYAKIGD/MWZaDfhJt1nZjPL3ZzdZBt/G8G8Hw2J1xOIrXWdNHFHPAvg==",
"license": "MIT"
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -6708,6 +6812,42 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -6722,6 +6862,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -8144,7 +8290,6 @@
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -9306,7 +9451,6 @@
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/universalify": {
@@ -9419,6 +9563,15 @@
"node": ">=10.12.0"
}
},
"node_modules/validator": {
"version": "13.12.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+3
View File
@@ -20,11 +20,14 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/class-validator": "^0.13.4",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/typeorm": "^10.0.2",
"class-transformer": "^0.5.1",
"dotenv": "^16.4.5",
"mysql2": "^3.11.1",
"reflect-metadata": "^0.1.13",
+9 -1
View File
@@ -12,6 +12,9 @@ import { EjeEstrategico } from './entities/ejesEstrategicos.entity';
import { LineaProgramatica } from './entities/LineaProgramatica.entity';
import { TipoUsuarioEntity } from './entities/tipoUsuario.entity';
import { UsuarioEntity } from './entities/usuario.entity';
import { UsuarioController } from './usuario/usuario.controller';
import { JwtModule } from '@nestjs/jwt';
import * as process from "node:process";
config({ path: '.env' });
@Module({
imports: [
@@ -37,8 +40,13 @@ config({ path: '.env' });
UsuarioEntity,
],
}),
JwtModule.register({
global: true,
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: process.env.JWT_EXPIRES },
}),
],
controllers: [AppController],
controllers: [AppController, UsuarioController],
providers: [AppService],
})
export class AppModule {}
+25 -2
View File
@@ -1,4 +1,27 @@
import { Controller } from '@nestjs/common';
import {
BadRequestException,
Body,
Controller,
HttpCode,
HttpStatus,
Logger,
Post,
} from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginDTO } from '../dtos/loginDTO';
@Controller('auth')
export class AuthController {}
export class AuthController {
constructor(private readonly authService: AuthService) {}
@HttpCode(HttpStatus.OK)
@Post('login')
login(@Body() loginDto: LoginDTO): Promise<any> {
Logger.log('/auth/loin/', 'requested');
if (loginDto) {
return this.authService.signIn(loginDto);
} else {
throw new BadRequestException();
}
}
}
+37
View File
@@ -0,0 +1,37 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException();
}
try {
const payload = await this.jwtService.verifyAsync(token, {
secret: process.env.JWT_SECRET,
});
// 💡 We're assigning the payload to the request object here
// so that we can access it in our route handlers
request['user'] = payload;
} catch {
throw new UnauthorizedException();
}
return true;
}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
+7 -1
View File
@@ -1,9 +1,15 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { UsersService } from '../users/users.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsuarioEntity } from '../entities/usuario.entity';
@Module({
imports: [UsersModule, TypeOrmModule.forFeature([UsuarioEntity])],
providers: [AuthService, UsersService],
controllers: [AuthController],
providers: [AuthService]
exports: [AuthService],
})
export class AuthModule {}
+45 -2
View File
@@ -1,4 +1,47 @@
import { Injectable } from '@nestjs/common';
import {
BadRequestException,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { UsersService } from '../users/users.service';
import { LoginDTO } from '../dtos/loginDTO';
import { JwtService } from '@nestjs/jwt';
import { UsuarioEntity } from "../entities/usuario.entity";
@Injectable()
export class AuthService {}
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async signIn(loginDto: LoginDTO): Promise<any> {
let user: UsuarioEntity;
switch (loginDto.tipo_usuario) {
case 1:
// Administrador
break;
case 2:
// Alumno
user = await this.usersService.findStudent(loginDto);
break;
case 3:
// Trabajadores académicos o base
user = await this.usersService.findWorker(loginDto);
default:
throw new BadRequestException();
break;
}
if (user === null) {
throw new UnauthorizedException();
}
const payload = { id: user.id, userType: user.tipo_usuario_id };
const access_token = await this.jwtService.signAsync(payload);
return user;
}
}
+18
View File
@@ -0,0 +1,18 @@
import { IsDefined, IsNotEmpty, IsNumber, IsString } from "@nestjs/class-validator";
export class LoginDTO {
@IsString()
@IsNotEmpty()
@IsDefined()
readonly numero_identificacion: string;
@IsString()
readonly rfc: string;
@IsString()
readonly fecha_nacimiento: string;
@IsNumber()
@IsNotEmpty()
readonly tipo_usuario: number;
}
+5 -2
View File
@@ -18,12 +18,15 @@ export class UsuarioEntity {
@Column('text')
numero_identificacion: string;
@Column('date', { nullable: true })
fecha_nacimiento: Date;
@Column('text')
fecha_nacimiento: string;
@Column('text', { nullable: true })
rfc: string;
@Column({ name: 'tipo_usuario_id' })
tipo_usuario_id: number;
@ManyToOne(() => Carrera, (carrera) => carrera.usuarios, { nullable: true })
@JoinColumn({ name: 'carrera_id' })
carrera: Carrera;
+6 -1
View File
@@ -1,7 +1,12 @@
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsuarioEntity } from '../entities/usuario.entity';
import { UsuarioController } from '../usuario/usuario.controller';
@Module({
providers: [UsersService]
imports: [TypeOrmModule.forFeature([UsuarioEntity])],
providers: [UsersService],
controllers: [UsuarioController],
})
export class UsersModule {}
+37 -1
View File
@@ -1,7 +1,43 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { UsuarioEntity } from '../entities/usuario.entity';
import { Repository } from 'typeorm';
import { LoginDTO } from '../dtos/loginDTO';
export type User = any;
@Injectable()
export class UsersService {
constructor(
@InjectRepository(UsuarioEntity)
private usersRepository: Repository<UsuarioEntity>,
) {}
// findAll(): Promise<UsuarioEntity[]> {
// return this.usersRepository.find();
// }
findStudent(loginDto: LoginDTO): Promise<UsuarioEntity | null> {
const numero_identificacion = loginDto.numero_identificacion;
const fecha_nacimiento = loginDto.fecha_nacimiento;
return this.usersRepository.findOneBy({
numero_identificacion,
fecha_nacimiento,
});
}
findWorker(loginDto: LoginDTO): Promise<UsuarioEntity | null> {
const numero_identificacion = loginDto.numero_identificacion;
const rfc = loginDto.rfc;
return this.usersRepository.findOneBy({
numero_identificacion,
rfc,
});
}
// findOne(id: number): Promise<UsuarioEntity | null> {
// return this.usersRepository.findOneBy({ id });
// }
//
// async remove(id: number): Promise<void> {
// await this.usersRepository.delete(id);
// }
}
+18
View File
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsuarioController } from './usuario.controller';
describe('UsuarioController', () => {
let controller: UsuarioController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UsuarioController],
}).compile();
controller = module.get<UsuarioController>(UsuarioController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
+4
View File
@@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';
@Controller('usuario')
export class UsuarioController {}