src/middleware/keyclock.middleware.ts
Properties |
Type : string
|
Defined in src/middleware/keyclock.middleware.ts:18
|
email_verified |
Type : string
|
Defined in src/middleware/keyclock.middleware.ts:16
|
name |
Type : string
|
Defined in src/middleware/keyclock.middleware.ts:17
|
realm |
Type : any
|
Defined in src/middleware/keyclock.middleware.ts:21
|
roles |
Type : any
|
Defined in src/middleware/keyclock.middleware.ts:22
|
username |
Type : string
|
Defined in src/middleware/keyclock.middleware.ts:20
|
usuarioId |
Type : string
|
Defined in src/middleware/keyclock.middleware.ts:19
|
import { HttpService } from '@nestjs/axios';
import { HttpStatus, Injectable, Logger, NestMiddleware } from '@nestjs/common';
import { configENV } from '../../config-env';
import jwt, { JwtPayload } from 'jsonwebtoken';
const jwktopem = require('jwk-to-pem');
import moment from 'moment';
import { ExceptionError } from '../util/exception-error';
import { catchError, firstValueFrom } from 'rxjs';
const logForDev = (msg) => {
console.log('DEBUG', msg);
};
export class Session {
email_verified: string;
name: string;
email: string;
usuarioId: string;
username: string;
realm: any;
roles: any;
}
const freeAccess = (originalUrl) => {
if (originalUrl?.includes('/importa/')) return true;
switch (true) {
case originalUrl === '/':
case originalUrl === '/api-docs':
case originalUrl === '/application/client':
// case originalUrl.startsWith('/'):
return true;
default:
return false;
}
};
const getPayloadToken = (token) => jwt.decode(token, { complete: true });
const getRealm = (token) => {
const tokenDecoded = getPayloadToken(token) as any;
if (tokenDecoded) {
return tokenDecoded.payload.iss.split('/').slice(-1)[0];
}
return null;
};
const getRoles = (token) => {
const { payload }: JwtPayload = jwt.decode(token, { complete: true });
if (payload?.group && payload?.group.length) {
const roles = payload.group.map((group) =>
group.split('/')[2].toLowerCase(),
);
return roles;
}
const resource: { roles: string[] }[] = Object.values(
payload.resource_access,
);
return resource[0].roles;
};
// const roleVerified = (payloadToken, searchElement = 'Analista') => {
// const roles = Object.values(payloadToken.resource_access)[0].roles;
// if (roles.roles.length) {
// return roles.includes(searchElement);
// }
// logForDev('A permissão não é igual a "Analista"');
// return false;
// }
@Injectable()
export class MiddlewareKeyclock implements NestMiddleware {
private readonly logger = new Logger(MiddlewareKeyclock.name);
async use(req, res, next) {
try {
if (freeAccess(req.originalUrl)) {
next();
return;
}
const { headers } = req;
const { authorization } = headers;
if (!authorization) {
logForDev('Não recebeu o token');
throw ExceptionError(
'Você não está autorizado(a)',
HttpStatus.FORBIDDEN,
);
}
// Bearer lkasdjfksdfaDJKÇLÇLKASDA
const parts = authorization.split(' ');
if (parts.length !== 2) {
throw ExceptionError('Token error', HttpStatus.FORBIDDEN);
}
const [schema, token] = parts;
// Verifica se Schema tem a palavra Bearer
if (!/^Bearer$/i.test(schema)) {
throw ExceptionError('Token mal formado', HttpStatus.FORBIDDEN);
}
const tokenDecoded = getPayloadToken(token) as any;
if (!tokenDecoded.payload.exp) {
throw ExceptionError('Token inválido', HttpStatus.FORBIDDEN);
}
if (moment() > moment.unix(tokenDecoded.payload.exp)) {
throw ExceptionError('Sessão expirada', HttpStatus.UNAUTHORIZED);
}
// if (!roleVerified(tokenDecoded.payload)) {
// throw ExceptionError('Você não está autorizado(a)', 426);
// }
const realm = getRealm(token);
const roles = getRoles(token);
if (!realm) {
throw ExceptionError(
'Realm não encontrado no token',
HttpStatus.UNAUTHORIZED,
);
}
const get = async (urlPublicKey) => {
const httpService = new HttpService();
const { data } = await firstValueFrom(
httpService.get(urlPublicKey).pipe(
catchError((error) => {
this.logger.debug('Erro ao buscar certs');
this.logger.error(error.response.data);
throw { message: 'Algo deu errado' };
}),
),
);
return data;
};
const {
metodo_aceso,
ip_servidor,
endpoint_keycloak_realms,
endpoint_keycloak_certs,
} = configENV;
const urlPublicKey =
metodo_aceso +
ip_servidor +
endpoint_keycloak_realms +
realm +
endpoint_keycloak_certs;
const data = await get(urlPublicKey);
const { keys } = data;
let firstKey = undefined;
if (keys[0].alg == 'RS256') {
firstKey = keys[0];
} else {
firstKey = keys[1];
}
const pkey = jwktopem(firstKey);
const validacao = jwt.verify(token, pkey) as any;
if (validacao.sub) {
req.session = {
email_verified: validacao.email_verified,
name: validacao.name,
email: validacao.email,
usuarioId: validacao.sub,
username: validacao.preferred_username,
realm,
roles,
};
next();
}
} catch (error) {
const status = error.code ? error.code : HttpStatus.FORBIDDEN;
res.status(status).json(error);
// return res.sendStatus(error.code ? error.code : 426).json(error);
}
}
}