generated from HenriqueAmorim20/GEROcuidadoAPITemplate
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(#136) adiciona autenticacao controller e service
- Loading branch information
1 parent
5c25c4f
commit 7a89bc2
Showing
6 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { HttpResponse } from '../shared/classes/http-response'; | ||
import { AutenticacaoController } from './autenticacao.controller'; | ||
import { AutenticacaoService } from './autenticacao.service'; | ||
|
||
describe('AutenticacaoController', () => { | ||
let controller: AutenticacaoController; | ||
let service: AutenticacaoService; | ||
|
||
const mockAutenticacaoService = { | ||
login: jest.fn(), | ||
validateToken: jest.fn(), | ||
}; | ||
|
||
beforeEach(async () => { | ||
const module: TestingModule = await Test.createTestingModule({ | ||
imports: [], | ||
controllers: [AutenticacaoController], | ||
providers: [ | ||
{ | ||
provide: AutenticacaoService, | ||
useValue: mockAutenticacaoService, | ||
}, | ||
], | ||
}).compile(); | ||
|
||
controller = module.get<AutenticacaoController>(AutenticacaoController); | ||
service = module.get<AutenticacaoService>(AutenticacaoService); | ||
}); | ||
|
||
it('should be defined', () => { | ||
expect(controller).toBeDefined(); | ||
expect(service).toBeDefined(); | ||
}); | ||
|
||
it('should login', async () => { | ||
jest.spyOn(service, 'login').mockReturnValue(Promise.resolve('token')); | ||
|
||
expect(await controller.login({ email: 'a', senha: 'a' })).toEqual( | ||
new HttpResponse('token').onLogin(), | ||
); | ||
}); | ||
|
||
it('should validateToken', async () => { | ||
jest.spyOn(service, 'validateToken').mockReturnValue(true); | ||
|
||
expect(await controller.validateToken({ jwt: 'token' })).toEqual(true); | ||
}); | ||
|
||
it('should not validateToken', async () => { | ||
jest.spyOn(service, 'validateToken').mockImplementation(() => { | ||
throw new Error(); | ||
}); | ||
|
||
expect(await controller.validateToken({ jwt: 'token' })).toEqual(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Body, Controller, HttpCode, Post } from '@nestjs/common'; | ||
import { MessagePattern } from '@nestjs/microservices'; | ||
import { HttpResponse } from '../shared/classes/http-response'; | ||
import { PublicRoute } from '../shared/decorators/public-route.decorator'; | ||
import { Response } from '../shared/interceptors/data-transform.interceptor'; | ||
import { AutenticacaoService } from './autenticacao.service'; | ||
import { LoginDto } from './dto/login.dto'; | ||
|
||
@Controller() | ||
export class AutenticacaoController { | ||
constructor(private readonly _service: AutenticacaoService) {} | ||
|
||
@Post('login') | ||
@PublicRoute() | ||
@HttpCode(200) | ||
async login(@Body() body: LoginDto): Promise<Response<string>> { | ||
const jwtToken = await this._service.login(body); | ||
return new HttpResponse<string>(jwtToken).onLogin(); | ||
} | ||
|
||
@MessagePattern({ role: 'auth', cmd: 'check' }) | ||
async validateToken(data: { jwt: string }) { | ||
try { | ||
return this._service.validateToken(data.jwt); | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { ConfigModule, ConfigService } from '@nestjs/config'; | ||
import { JwtModule } from '@nestjs/jwt'; | ||
import { PassportModule } from '@nestjs/passport'; | ||
import { UsuarioModule } from '../usuario/usuario.module'; | ||
import { AutenticacaoController } from './autenticacao.controller'; | ||
import { AutenticacaoService } from './autenticacao.service'; | ||
import { JwtStrategy } from './jwt.strategy'; | ||
|
||
@Module({ | ||
imports: [ | ||
UsuarioModule, | ||
PassportModule, | ||
JwtModule.registerAsync({ | ||
imports: [ConfigModule], | ||
useFactory: (configService: ConfigService) => ({ | ||
secret: configService.get<string>('JWT_TOKEN_SECRET'), | ||
}), | ||
inject: [ConfigService], | ||
}), | ||
], | ||
controllers: [AutenticacaoController], | ||
providers: [AutenticacaoService, JwtStrategy], | ||
exports: [AutenticacaoService], | ||
}) | ||
export class AutenticacaoModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { BadRequestException, UnauthorizedException } from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
import { JwtService } from '@nestjs/jwt'; | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import bcrypt from 'bcrypt'; | ||
import { UsuarioService } from '../usuario/usuario.service'; | ||
import { AutenticacaoService } from './autenticacao.service'; | ||
|
||
describe('AutenticacaoService', () => { | ||
let service: AutenticacaoService; | ||
let usuarioService: UsuarioService; | ||
let configService: ConfigService; | ||
let jwtService: JwtService; | ||
|
||
const mockUsuarioService = { | ||
findByEmail: jest.fn(), | ||
}; | ||
|
||
const mockConfigService = { | ||
get: jest.fn(), | ||
}; | ||
|
||
const mockJwtService = { | ||
sign: jest.fn(), | ||
verify: jest.fn(), | ||
}; | ||
|
||
beforeEach(async () => { | ||
const module: TestingModule = await Test.createTestingModule({ | ||
providers: [ | ||
AutenticacaoService, | ||
{ provide: UsuarioService, useValue: mockUsuarioService }, | ||
{ provide: ConfigService, useValue: mockConfigService }, | ||
{ provide: JwtService, useValue: mockJwtService }, | ||
], | ||
}).compile(); | ||
|
||
service = module.get<AutenticacaoService>(AutenticacaoService); | ||
usuarioService = module.get<UsuarioService>(UsuarioService); | ||
configService = module.get<ConfigService>(ConfigService); | ||
jwtService = module.get<JwtService>(JwtService); | ||
}); | ||
|
||
it('should be defined', () => { | ||
expect(service).toBeDefined(); | ||
}); | ||
|
||
it('should not login - no email found', async () => { | ||
jest.spyOn(usuarioService, 'findByEmail').mockReturnValue(undefined as any); | ||
|
||
expect(service.login({ email: 'a', senha: '1' })).rejects.toThrow( | ||
new BadRequestException('Este email não está cadastrado!'), | ||
); | ||
}); | ||
|
||
it('should not login - wrong password', async () => { | ||
jest.spyOn(usuarioService, 'findByEmail').mockReturnValue('a' as any); | ||
jest | ||
.spyOn(bcrypt, 'compare') | ||
.mockImplementation((pass: string | Buffer, hash: string) => | ||
Promise.resolve(false), | ||
); | ||
|
||
expect(service.login({ email: 'a', senha: '1' })).rejects.toThrow( | ||
new UnauthorizedException('Senha incorreta!'), | ||
); | ||
}); | ||
|
||
it('should login', async () => { | ||
jest.spyOn(configService, 'get').mockReturnValue('12h'); | ||
jest.spyOn(jwtService, 'sign').mockReturnValue('token'); | ||
jest.spyOn(usuarioService, 'findByEmail').mockReturnValue('a' as any); | ||
jest | ||
.spyOn(bcrypt, 'compare') | ||
.mockImplementation((pass: string | Buffer, hash: string) => | ||
Promise.resolve(true), | ||
); | ||
|
||
expect(await service.login({ email: 'a', senha: '1' })).toEqual('token'); | ||
}); | ||
|
||
it('should validate token', () => { | ||
jest.spyOn(jwtService, 'verify').mockReturnValue(true as any); | ||
|
||
expect(service.validateToken('token')).toEqual(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { | ||
BadRequestException, | ||
Injectable, | ||
UnauthorizedException, | ||
} from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
import { JwtService } from '@nestjs/jwt'; | ||
import bcrypt from 'bcrypt'; | ||
import { UsuarioService } from '../usuario/usuario.service'; | ||
import { LoginDto } from './dto/login.dto'; | ||
|
||
@Injectable() | ||
export class AutenticacaoService { | ||
constructor( | ||
private readonly _usuarioService: UsuarioService, | ||
private readonly _jwtService: JwtService, | ||
private readonly _configService: ConfigService, | ||
) {} | ||
|
||
async login({ email, senha }: LoginDto): Promise<string> { | ||
const userFound = await this._usuarioService.findByEmail(email); | ||
|
||
if (!userFound) { | ||
throw new BadRequestException('Este email não está cadastrado!'); | ||
} | ||
|
||
await this.verifyPassword(senha, userFound.senha); | ||
|
||
const JwtPayload = { | ||
id: userFound.id, | ||
email: userFound.email, | ||
nome: userFound.nome, | ||
admin: userFound.admin, | ||
}; | ||
|
||
const expiresIn = this._configService.get('JWT_TOKEN_EXPIRES_IN'); | ||
|
||
return this._jwtService.sign(JwtPayload, { expiresIn }); | ||
} | ||
|
||
private async verifyPassword(senha: string, hash: string) { | ||
// TODO a senha deve vir do front como um base64 | ||
const isMatch = await bcrypt.compare(senha, hash); | ||
|
||
if (!isMatch) { | ||
throw new UnauthorizedException('Senha incorreta!'); | ||
} | ||
} | ||
|
||
validateToken(jwt: string) { | ||
return this._jwtService.verify(jwt); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { IsEmail, IsNotEmpty, IsString } from 'class-validator'; | ||
|
||
export class LoginDto { | ||
@IsString() | ||
@IsNotEmpty() | ||
@IsEmail() | ||
email!: string; | ||
|
||
@IsString() | ||
@IsNotEmpty() | ||
senha!: string; | ||
} |