Node

Microserviço para Autenticação e Gerenciamento de Usuários - REST API

Middleware para Método de Autenticação Basic Auth do HTTP

É uma forma de autenticação baseada no protocolo HTTP.
O objetivo é reaproveitar o método, ao criar um Middleware podemos invocar ele em vários outros endpoints.

Extender o @types/express

Extender o @types/express incluindo o type User no Request para poder propagar o usuário para o próximo middleware.
Criar um arquivo de definição para o express src/@types/express.d.ts, é uma espécie de "interface".

                            import { User } from '../models/user.model';

                            declare module 'express-serve-static-core' {
                                interface Request {
                                    user?: User | null;
                                }
                            }
                        
Isso pode ser feito para incluir qualquer tipo de atributo customizado.

Criar o Middleware

Criar o Middleware em src/middlewares/basic-authentication.ts
Colocar o user dentro da requisição para ficar acessível em todas as rotas.
Chamar o next() sem passar erro para que ele continue propagando entre os middlewares e as rotas.
Se passar algum erro ele irá para o middleware de Error Handler em src/middlewares/error-handler.ts

                            import { Request, Response, NextFunction } from 'express';
                            import ForbiddenError from '../models/errors/forbidden.error.model';
                            import userRepository from '../repositories/user.repository';
                            
                            async function basicAuthentication(req: Request, res: Response, next: NextFunction){
                                try{
                                    // Recuperar usuário e senha do header da requisição
                                    const authorizationHeader = req.headers['authorization'];
                                    if (!authorizationHeader) {
                                        throw new ForbiddenError('Credenciais não informadas');
                                    } 
                                    const [authorizationType, token] = authorizationHeader?.split(" "); 
                                    if(authorizationType !== 'Basic' || !token){
                                        throw new ForbiddenError('Tipo de autenticação inválida');
                                    }
                            
                                    // Criar buffer a partir do Token que está em Base64 e converter para string codificação UTF-8
                                    const tokenContent = Buffer.from(token, 'base64').toString('utf-8');
                                    const [userName, userPassword] = tokenContent.split(":"); 
                                    if(!userName || !userPassword){
                                        throw new ForbiddenError('Credenciais não preenchidas');
                                    }
                            
                                    // Obter usuário e senha da Database
                                    const user = await userRepository.byUserNameAndPassword(userName, userPassword);
                                    if(!user){
                                        throw new ForbiddenError('Usuário e/ou senha inválidos');
                                    }

                                    // Colocar o user dentro da requisição
                                    req.user = user;
                                    next();

                                }catch(error){
                                    next(error);
                                }
                            };
                            
                            export default basicAuthentication;
                        

Configurar o Middleware no Server

Neste caso, NÃO vamos configurar o middleware no server src/server.ts pois não queremos que ele seja global, mas que seja usado somente na rota de autenticação, portanto local.

Configurar o Middleware na rota de autenticação

Configurar o Middleware basicAuthentication na rota de autorização em src/routes/authorization.route.ts
Recuperar o user do request.

                            import { Router, Request, Response, NextFunction } from 'express';
                            import basicAuthentication from '../middlewares/basic-authentication';
                            import JWT from 'jsonwebtoken';
                            import { StatusCodes } from 'http-status-codes';
                            import ForbiddenError from '../models/errors/forbidden.error.model';
                                                        
                            const authorizationRouter = Router();
                            
                            authorizationRouter.post('/token', basicAuthentication, async (req: Request, res: Response, next: NextFunction) => {
                                try{
                                    // Recuperar o user da request
                                    const user = req.user;
                                    if(!user){
                                        throw new ForbiddenError('Usuário não informado!');
                                    }
                            
                                    // Gerar token JWT 
                                    const jwtPayLoad   = {userName: user.userName};
                                    const jwtSecretKey = process.env.JWT_SECRET_KEY;
                                    const jwtOptions   = {subject: user?.uuid};
                                    const jwtToken = JWT.sign(jwtPayLoad, jwtSecretKey, jwtOptions);
                            
                                    // Response Token
                                    res.status(StatusCodes.OK).json({ token: jwtToken });
                                }catch(error){
                                    next(error);
                                }
                            });
                            
                            export default authorizationRouter;