Skip to content

Commit

Permalink
Merge pull request #4 from fga-eps-mds/feature/#136-autenticacao
Browse files Browse the repository at this point in the history
Feature/#136 autenticacao
  • Loading branch information
HenriqueAmorim20 authored Oct 24, 2023
2 parents f5152f3 + 8984bd6 commit b511b4e
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 7 deletions.
4 changes: 4 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ DB_USERNAME=postgres
DB_PASS=postgres
DB_DATABASE=gerocuidado-saude-db
DB_PORT=5003

## TCP
AUTH_HOST=gerocuidado-usuario-api
AUTH_PORT=4001
4 changes: 4 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ DB_USERNAME=postgres
DB_PASS=postgres
DB_DATABASE=gerocuidado-saude-db-test
DB_PORT=5003

## TCP
AUTH_HOST=gerocuidado-usuario-api
AUTH_PORT=4001
6 changes: 6 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ services:
- DB_PASS=postgres
- DB_DATABASE=gerocuidado-saude-db
- DB_PORT=5003
- AUTH_HOST=gerocuidado-usuario-api-prod
- AUTH_PORT=4001
ports:
- '3003:3003'
depends_on:
- gerocuidado-saude-db
networks:
- gerocuidado-saude-net
- gerocuidado-apis-net

gerocuidado-saude-db:
build:
Expand All @@ -36,3 +39,6 @@ services:
networks:
gerocuidado-saude-net:
driver: bridge
gerocuidado-apis-net:
name: gerocuidado-apis-net
external: true
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest --no-cache --colors --detectOpenHandles",
"test:watch": "jest --watchAll",
"test:cov": "jest --coverage --colors",
"test:cov": "jest --forceExit --detectOpenHandles --runInBand --coverage --colors",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --forceExit --detectOpenHandles --colors --config ./e2e/jest-e2e.json",
"test:e2e:cov": "jest --forceExit --detectOpenHandles --colors --coverage --config ./e2e/jest-e2e.json",
"test:e2e:cov": "jest --forceExit --detectOpenHandles --runInBand --colors --coverage --config ./e2e/jest-e2e.json",
"test:e2e:watch": "jest --detectOpenHandles --config ./e2e/jest-e2e.json --watchAll",
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js",
"typeorm:create": "npm run typeorm migration:create",
Expand Down
26 changes: 24 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { APP_GUARD } from '@nestjs/core';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AutenticacaoGuard } from './autenticacao.guard';
import { DbModule } from './config/db/db.module';
import { DbService } from './config/db/db.service';

Expand All @@ -16,9 +19,28 @@ const ENV = process.env.NODE_ENV;
imports: [ConfigModule, DbModule],
useClass: DbService,
}),
ClientsModule.registerAsync([
{
name: 'AUTH_CLIENT',
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
transport: Transport.TCP,
options: {
host: configService.get('AUTH_HOST'),
port: configService.get('AUTH_PORT'),
},
}),
inject: [ConfigService],
},
]),
DbModule,
],
controllers: [],
providers: [],
providers: [
{
provide: APP_GUARD,
useClass: AutenticacaoGuard,
},
],
})
export class AppModule {}
76 changes: 76 additions & 0 deletions src/autenticacao.guard.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Test, TestingModule } from '@nestjs/testing';
import { of } from 'rxjs';
import { AutenticacaoGuard } from './autenticacao.guard';

describe('AutenticacaoGuard', () => {
let guard: AutenticacaoGuard;
let reflector: Reflector;

const mockClientProxy = {
send: jest.fn(),
};

const mockContext = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue({
headers: {
authorization: 'Bearer token',
},
}),
}),
getHandler: jest.fn(),
getClass: jest.fn(),
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AutenticacaoGuard,
{
provide: 'AUTH_CLIENT',
useValue: mockClientProxy,
},
Reflector,
],
}).compile();

guard = module.get<AutenticacaoGuard>(AutenticacaoGuard);
reflector = module.get<Reflector>(Reflector);
});

it('should be defined', () => {
expect(guard).toBeDefined();
});

it('should pass if route is public', async () => {
jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(true);

const result = await guard.canActivate(mockContext as any);

expect(result).toBe(true);
});

it('should pass if authentication is successful', async () => {
jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(false);
mockClientProxy.send.mockReturnValue(of(true));

const result = await guard.canActivate(mockContext as any);

expect(result).toBe(true);
});

it('should not pass if authentication is unsuccessful', async () => {
jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(false);
mockClientProxy.send.mockReturnValue(of(false));

guard
.canActivate(mockContext as any)
.catch((err) =>
expect(err).toEqual(
new UnauthorizedException('Usuário não autenticado!'),
),
);
});
});
43 changes: 43 additions & 0 deletions src/autenticacao.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ClientProxy } from '@nestjs/microservices';
import { lastValueFrom, timeout } from 'rxjs';
import { IS_PUBLIC_KEY } from './shared/decorators/public-route.decorator';

@Injectable()
export class AutenticacaoGuard implements CanActivate {
constructor(
@Inject('AUTH_CLIENT')
private readonly _client: ClientProxy,
private readonly _reflector: Reflector,
) {}

async canActivate(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();
const jwt = req.headers['authorization']?.split(' ')[1];

const isPublic = this._reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);

if (isPublic) return true;

const request = this._client
.send({ role: 'auth', cmd: 'check' }, { jwt })
.pipe(timeout(5000));
const response = await lastValueFrom(request);

if (!response) {
throw new UnauthorizedException('Usuário não autenticado!');
}

return true;
}
}
8 changes: 8 additions & 0 deletions src/shared/decorators/public-route.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { PublicRoute } from './public-route.decorator';

describe('Pagination', () => {
it('should be defined', () => {
PublicRoute();
expect(PublicRoute).toBeDefined();
});
});

0 comments on commit b511b4e

Please sign in to comment.