This commit is contained in:
David Arranz 2025-02-07 12:14:36 +01:00
parent bc6e4e594f
commit eef6e6fa97
18 changed files with 173 additions and 154 deletions

1
.gitignore vendored
View File

@ -38,6 +38,7 @@ error-*.log
# Misc # Misc
.DS_Store .DS_Store
*.pem *.pem
*-audit.json
#Jetbrains #Jetbrains
.idea .idea

View File

@ -1,6 +1,6 @@
import { logger } from "@common/infrastructure/logger"; import { logger } from "@common/infrastructure/logger";
import { globalErrorHandler } from "@common/presentation"; import { globalErrorHandler } from "@common/presentation";
import { initializePassportAuthProvide } from "@contexts/auth/infraestructure"; import { createAuthProvider } from "@contexts/auth/infraestructure";
import dotenv from "dotenv"; import dotenv from "dotenv";
import express, { Application } from "express"; import express, { Application } from "express";
import helmet from "helmet"; import helmet from "helmet";
@ -24,9 +24,9 @@ export function createApp(): Application {
app.use(responseTime()); // set up the response-time middleware app.use(responseTime()); // set up the response-time middleware
// Inicializar Passport // Inicializar Auth Provider
app.use((req, res, next) => { app.use((req, res, next) => {
initializePassportAuthProvide(); createAuthProvider().initialize();
next(); next();
}); });

View File

@ -1,10 +1,17 @@
import { Result, UniqueID } from "@common/domain"; import { Result, UniqueID } from "@common/domain";
import { AuthenticatedUser, EmailAddress, HashPassword, PlainPassword, Username } from "../domain"; import {
AuthenticatedUser,
EmailAddress,
HashPassword,
PlainPassword,
TabContext,
Username,
} from "../domain";
import { IJWTPayload } from "../infraestructure";
export interface IAuthService { export interface IAuthService {
generateAccessToken(payload: object): string; generateAccessToken(payload: IJWTPayload): string;
generateRefreshToken(payload: object): string; generateRefreshToken(payload: IJWTPayload): string;
verifyToken(token: string): Promise<AuthenticatedUser | null>;
registerUser(params: { registerUser(params: {
username: Username; username: Username;
@ -20,6 +27,7 @@ export interface IAuthService {
Result< Result<
{ {
user: AuthenticatedUser; user: AuthenticatedUser;
tabContext: TabContext;
tokens: { tokens: {
accessToken: string; accessToken: string;
refreshToken: string; refreshToken: string;
@ -31,8 +39,5 @@ export interface IAuthService {
logoutUser(params: { email: EmailAddress; tabId: UniqueID }): Promise<Result<void, Error>>; logoutUser(params: { email: EmailAddress; tabId: UniqueID }): Promise<Result<void, Error>>;
verifyUser(params: { getUserByEmail(params: { email: EmailAddress }): Promise<Result<AuthenticatedUser, Error>>;
email: EmailAddress;
plainPassword: PlainPassword;
}): Promise<Result<AuthenticatedUser, Error>>;
} }

View File

@ -1,19 +1,18 @@
import { Result, UniqueID } from "@common/domain"; import { Result, UniqueID } from "@common/domain";
import { ITransactionManager } from "@common/infrastructure/database"; import { ITransactionManager } from "@common/infrastructure/database";
import jwt from "jsonwebtoken";
import { import {
AuthenticatedUser, AuthenticatedUser,
EmailAddress, EmailAddress,
HashPassword, HashPassword,
IAuthenticatedUserRepository, IAuthenticatedUserRepository,
PlainPassword,
TabContext, TabContext,
Username, Username,
} from "../domain"; } from "../domain";
import { ITabContextRepository } from "../domain/repositories/tab-context-repository.interface"; import { ITabContextRepository } from "../domain/repositories/tab-context-repository.interface";
import { JwtHelper } from "../infraestructure/passport/jwt.helper";
import { IJWTPayload } from "../infraestructure/passport/passport-auth-provider";
import { IAuthService } from "./auth-service.interface"; import { IAuthService } from "./auth-service.interface";
const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey";
const ACCESS_EXPIRATION = process.env.JWT_ACCESS_EXPIRATION || "1h"; const ACCESS_EXPIRATION = process.env.JWT_ACCESS_EXPIRATION || "1h";
const REFRESH_EXPIRATION = process.env.JWT_REFRESH_EXPIRATION || "7d"; const REFRESH_EXPIRATION = process.env.JWT_REFRESH_EXPIRATION || "7d";
@ -32,16 +31,12 @@ export class AuthService implements IAuthService {
this._transactionManager = transactionManager; this._transactionManager = transactionManager;
} }
generateAccessToken(payload: object): string { generateAccessToken(payload: IJWTPayload): string {
return jwt.sign(payload, SECRET_KEY, { expiresIn: ACCESS_EXPIRATION }); return JwtHelper.generateToken(payload, ACCESS_EXPIRATION);
} }
generateRefreshToken(payload: object): string { generateRefreshToken(payload: IJWTPayload): string {
return jwt.sign(payload, SECRET_KEY, { expiresIn: REFRESH_EXPIRATION }); return JwtHelper.generateToken(payload, REFRESH_EXPIRATION);
}
verifyToken(token: string): any {
return jwt.verify(token, SECRET_KEY);
} }
/** /**
@ -104,6 +99,7 @@ export class AuthService implements IAuthService {
Result< Result<
{ {
user: AuthenticatedUser; user: AuthenticatedUser;
tabContext: TabContext;
tokens: { tokens: {
accessToken: string; accessToken: string;
refreshToken: string; refreshToken: string;
@ -145,7 +141,9 @@ export class AuthService implements IAuthService {
return Result.fail(new Error("Error creating user context")); return Result.fail(new Error("Error creating user context"));
} }
await this._tabContactRepo.registerContextByTabId(contextOrError.data, transaction); const tabContext = contextOrError.data;
await this._tabContactRepo.registerContextByTabId(tabContext, transaction);
// 🔹 Generar Access Token y Refresh Token // 🔹 Generar Access Token y Refresh Token
const accessToken = this.generateAccessToken({ const accessToken = this.generateAccessToken({
@ -157,10 +155,14 @@ export class AuthService implements IAuthService {
const refreshToken = this.generateRefreshToken({ const refreshToken = this.generateRefreshToken({
userId: user.id.toString(), userId: user.id.toString(),
email: email.toString(),
tabId: tabId.toString(),
roles: ["USER"],
}); });
return Result.ok({ return Result.ok({
user, user,
tabContext,
tokens: { tokens: {
accessToken, accessToken,
refreshToken, refreshToken,
@ -213,27 +215,17 @@ export class AuthService implements IAuthService {
} }
} }
async verifyUser(params: { async getUserByEmail(params: { email: EmailAddress }): Promise<Result<AuthenticatedUser, Error>> {
email: EmailAddress;
plainPassword: PlainPassword;
}): Promise<Result<AuthenticatedUser, Error>> {
try { try {
return await this._transactionManager.complete(async (transaction) => { return await this._transactionManager.complete(async (transaction) => {
const { email, plainPassword } = params; const { email } = params;
const userResult = await this._userRepo.getUserByEmail(email, transaction); const userResult = await this._userRepo.getUserByEmail(email, transaction);
if (userResult.isFailure || !userResult.data) { if (userResult.isFailure || !userResult.data) {
return Result.fail(new Error("Invalid email or password")); return Result.fail(new Error("Invalid email or password"));
} }
const user = userResult.data; return Result.ok(userResult.data);
const isValidPassword = await user.verifyPassword(plainPassword);
if (!isValidPassword) {
return Result.fail(new Error("Invalid email or password"));
}
return Result.ok(user);
}); });
} catch (error: unknown) { } catch (error: unknown) {
return Result.fail(error as Error); return Result.fail(error as Error);

View File

@ -19,9 +19,9 @@ export interface IAuthenticatedUser {
isUser: boolean; isUser: boolean;
isAdmin: boolean; isAdmin: boolean;
contexts: ICollection<QuoteItem>;
verifyPassword(candidatePassword: PlainPassword): Promise<boolean>; verifyPassword(candidatePassword: PlainPassword): Promise<boolean>;
hasRole(role: string): boolean;
hasRoles(roles: string[]): boolean;
getRoles(): string[]; getRoles(): string[];
toPersistenceData(): any; toPersistenceData(): any;
} }
@ -43,10 +43,6 @@ export class AuthenticatedUser
return Result.ok(user); return Result.ok(user);
} }
private _hasRole(role: string): boolean {
return (this._props.roles || []).some((r) => r === role);
}
verifyPassword(candidatePassword: PlainPassword): Promise<boolean> { verifyPassword(candidatePassword: PlainPassword): Promise<boolean> {
return this._props.hashPassword.verifyPassword(candidatePassword.toString()); return this._props.hashPassword.verifyPassword(candidatePassword.toString());
} }
@ -55,6 +51,14 @@ export class AuthenticatedUser
return this._props.roles; return this._props.roles;
} }
hasRole(role: string): boolean {
return (this._props.roles || []).some((r) => r === role);
}
hasRoles(roles: string[]): boolean {
return roles.map((rol) => this.hasRole(rol)).some((value) => value != false);
}
get username(): Username { get username(): Username {
return this._props.username; return this._props.username;
} }
@ -64,11 +68,11 @@ export class AuthenticatedUser
} }
get isUser(): boolean { get isUser(): boolean {
return this._hasRole("user"); return this.hasRole("user");
} }
get isAdmin(): boolean { get isAdmin(): boolean {
return this._hasRole("admin"); return this.hasRole("admin");
} }
/** /**

View File

@ -1,4 +1,3 @@
export * from "./jwt.helper";
export * from "./mappers"; export * from "./mappers";
export * from "./passport"; export * from "./passport";
export * from "./sequelize"; export * from "./sequelize";

View File

@ -1,9 +1,7 @@
import { createAuthService } from "@contexts/auth/application"; import { createAuthService, createTabContextService } from "../../application";
import { PassportAuthProvider } from "./passport-auth-provider"; import { IJWTPayload, PassportAuthProvider } from "./passport-auth-provider";
export const createPassportAuthProvider = () => { export { IJWTPayload };
const _authService = createAuthService();
return new PassportAuthProvider(_authService);
};
export const initializePassportAuthProvide = () => createPassportAuthProvider(); export const createAuthProvider = () =>
new PassportAuthProvider(createAuthService(), createTabContextService());

View File

@ -1,6 +1,8 @@
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey"; const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey";
const ACCESS_EXPIRATION = process.env.JWT_ACCESS_EXPIRATION || "1h";
const REFRESH_EXPIRATION = process.env.JWT_REFRESH_EXPIRATION || "7d";
export class JwtHelper { export class JwtHelper {
static generateToken(payload: object, expiresIn = "1h"): string { static generateToken(payload: object, expiresIn = "1h"): string {

View File

@ -1,4 +1,6 @@
import { Result, UniqueID } from "@common/domain";
import { IAuthService } from "@contexts/auth/application"; import { IAuthService } from "@contexts/auth/application";
import { ITabContextService } from "@contexts/auth/application/tab-context-service.interface";
import { AuthenticatedUser, EmailAddress, PlainPassword } from "@contexts/auth/domain"; import { AuthenticatedUser, EmailAddress, PlainPassword } from "@contexts/auth/domain";
import passport from "passport"; import passport from "passport";
import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt"; import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt";
@ -6,35 +8,100 @@ import { Strategy as LocalStrategy } from "passport-local";
const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey"; const SECRET_KEY = process.env.JWT_SECRET || "supersecretkey";
export interface IJWTPayload {
userId: string;
email: string;
tabId: string;
roles: string[];
}
export class PassportAuthProvider { export class PassportAuthProvider {
private readonly _authService: IAuthService; private readonly _authService: IAuthService;
private readonly _tabContextService: ITabContextService;
private async _verifyUser(email: string, password: string): Promise<AuthenticatedUser | null> { private async _getUserByEmailAndPassword(
email: string,
password: string
): Promise<Result<AuthenticatedUser, Error>> {
const emailVO = EmailAddress.create(email); const emailVO = EmailAddress.create(email);
if (emailVO.isFailure) return Promise.resolve(null); if (emailVO.isFailure) {
return Result.fail(emailVO.error);
}
const plainPasswordVO = PlainPassword.create(password); const plainPasswordVO = PlainPassword.create(password);
if (plainPasswordVO.isFailure) return Promise.resolve(null); if (plainPasswordVO.isFailure) {
return Result.fail(plainPasswordVO.error);
}
const userResult = await this._authService.verifyUser({ const userResult = await this._authService.getUserByEmail({
email: emailVO.data, email: emailVO.data,
plainPassword: plainPasswordVO.data,
}); });
if (userResult.isFailure || !userResult.data) { if (userResult.isFailure || !userResult.data) {
return Promise.resolve(null); return Result.fail(new Error("Invalid email or password"));
} }
const user = userResult.data; const user = userResult.data;
const isValidPassword = await user.verifyPassword(plainPasswordVO.data); const isValidPassword = await user.verifyPassword(plainPasswordVO.data);
return !isValidPassword ? Promise.resolve(null) : Promise.resolve(user); if (!isValidPassword) {
return Result.fail(new Error("Invalid email or password"));
}
return Result.ok(user);
}
private async _getUserAndContextByToken(token: IJWTPayload) {
const { userId, email, roles, tabId } = token;
const userIdVO = UniqueID.create(userId);
const tabIdVO = UniqueID.create(tabId);
const emailVO = EmailAddress.create(email!);
const okOrError = Result.combine([userIdVO, tabIdVO, emailVO]);
if (okOrError.isFailure) {
return Result.fail(okOrError.error.message);
}
const userResult = await this._authService.getUserByEmail({
email: emailVO.data,
});
if (userResult.isFailure) {
return Result.fail(new Error("Invalid token data"));
}
const user = userResult.data;
const checkUserId = user.id.equals(userIdVO.data);
const checkRoles = user.hasRoles(roles);
if (!checkUserId || !checkRoles) {
return Result.fail(new Error("Invalid token data"));
}
const tabResult = await this._tabContextService.getContextByTabId(tabIdVO.data);
if (tabResult.isFailure) {
return Result.fail(new Error("Invalid token data"));
}
const tabContext = tabResult.data;
return Result.ok({
user,
tabContext,
});
}
constructor(authService: IAuthService, tabContextService: ITabContextService) {
this._authService = authService;
this._tabContextService = tabContextService;
} }
/** /**
* 🔹 Configura PassportJS * 🔹 Configura PassportJS
*/ */
initializePassport(): void { initialize(): void {
const jwtOptions = { const jwtOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: SECRET_KEY, secretOrKey: SECRET_KEY,
@ -42,10 +109,12 @@ export class PassportAuthProvider {
passport.use( passport.use(
"jwt", "jwt",
new JwtStrategy(jwtOptions, (tokenPayload, done) => { new JwtStrategy(jwtOptions, async (tokenPayload, done) => {
try { try {
console.log(tokenPayload); const result = await this._getUserAndContextByToken(tokenPayload);
return done(null, tokenPayload); return result.isSuccess
? done(null, result)
: done(result.error, false, { message: "Invalid JWT data" });
} catch (error) { } catch (error) {
return done(error, false); return done(error, false);
} }
@ -58,7 +127,7 @@ export class PassportAuthProvider {
{ usernameField: "email", passwordField: "password" }, { usernameField: "email", passwordField: "password" },
async (email, password, done) => { async (email, password, done) => {
try { try {
const user = await this._verifyUser(email, password); const user = await this._getUserByEmailAndPassword(email, password);
return user return user
? done(null, user) ? done(null, user)
: done(null, false, { message: "Invalid email or password" }); : done(null, false, { message: "Invalid email or password" });
@ -72,8 +141,7 @@ export class PassportAuthProvider {
passport.initialize(); passport.initialize();
} }
constructor(authService: IAuthService) { authenticateJWT() {
this._authService = authService; return passport.authenticate("jwt", { session: false });
this.initializePassport();
} }
} }

View File

@ -1,19 +1,6 @@
import { import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize";
DataTypes,
InferAttributes,
InferCreationAttributes,
Model,
NonAttribute,
Sequelize,
} from "sequelize";
import { TabContextCreationAttributes, TabContextModel } from "./tab-context.model";
export type AuthUserCreationAttributes = InferCreationAttributes< export type AuthUserCreationAttributes = InferCreationAttributes<AuthUserModel>;
AuthUserModel,
{ omit: "contexts" }
> & {
contexts: TabContextCreationAttributes[];
};
export class AuthUserModel extends Model< export class AuthUserModel extends Model<
InferAttributes<AuthUserModel>, InferAttributes<AuthUserModel>,
@ -24,22 +11,11 @@ export class AuthUserModel extends Model<
return Promise.resolve(); return Promise.resolve();
}*/ }*/
static associate(connection: Sequelize) {
const { TabContextModel } = connection.models;
AuthUserModel.hasMany(TabContextModel, {
as: "contexts",
foreignKey: "user_id",
onDelete: "CASCADE",
});
}
declare id: string; declare id: string;
declare username: string; declare username: string;
declare email: string; declare email: string;
declare hash_password: string; declare hash_password: string;
declare roles: string[]; declare roles: string[];
declare contexts: NonAttribute<TabContextModel[]>;
} }
export default (sequelize: Sequelize) => { export default (sequelize: Sequelize) => {

View File

@ -1,21 +1,10 @@
import { import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize";
DataTypes,
InferAttributes,
InferCreationAttributes,
Model,
NonAttribute,
Sequelize,
} from "sequelize";
import { AuthUserModel } from "./auth-user.model";
export type TabContextCreationAttributes = InferCreationAttributes< export type TabContextCreationAttributes = InferCreationAttributes<TabContextModel>;
TabContextModel,
{ omit: "user" }
>;
export class TabContextModel extends Model< export class TabContextModel extends Model<
InferAttributes<TabContextModel, { omit: "user" }>, InferAttributes<TabContextModel>,
InferCreationAttributes<TabContextModel, { omit: "user" }> InferCreationAttributes<TabContextModel>
> { > {
// To avoid table creation // To avoid table creation
/*static async sync(): Promise<any> { /*static async sync(): Promise<any> {
@ -23,21 +12,11 @@ export class TabContextModel extends Model<
}*/ }*/
static associate(connection: Sequelize) { static associate(connection: Sequelize) {
const { AuthUserModel } = connection.models; const { AuthUserModel } = connection.models;
TabContextModel.belongsTo(AuthUserModel, {
as: "user",
foreignKey: "user_id",
onDelete: "CASCADE",
});
} }
declare id: string; declare id: string;
declare tab_id: string; declare tab_id: string;
declare user_id: string; declare user_id: string;
declare company_id: string;
declare branch_id: string;
declare user: NonAttribute<AuthUserModel>;
} }
export default (sequelize: Sequelize) => { export default (sequelize: Sequelize) => {
@ -55,14 +34,6 @@ export default (sequelize: Sequelize) => {
type: DataTypes.UUID, type: DataTypes.UUID,
allowNull: false, allowNull: false,
}, },
company_id: {
type: DataTypes.UUID,
allowNull: false,
},
branch_id: {
type: DataTypes.UUID,
allowNull: false,
},
}, },
{ {
sequelize, sequelize,

View File

@ -26,17 +26,17 @@ class LoginController extends ExpressController {
return this.clientError("Invalid input data", resultValidation.error); return this.clientError("Invalid input data", resultValidation.error);
} }
const userOrError = await this._authService.loginUser({ const loginResultOrError = await this._authService.loginUser({
email: emailVO.data, email: emailVO.data,
plainPassword: plainPasswordVO.data, plainPassword: plainPasswordVO.data,
tabId: tabIdVO.data, tabId: tabIdVO.data,
}); });
if (userOrError.isFailure) { if (loginResultOrError.isFailure) {
return this.unauthorizedError(userOrError.error.message); return this.unauthorizedError(loginResultOrError.error.message);
} }
return this.created(this._presenter.map(userOrError.data)); return this.created(this._presenter.map(loginResultOrError.data));
} }
} }

View File

@ -1,9 +1,10 @@
import { AuthenticatedUser } from "@contexts/auth/domain"; import { AuthenticatedUser, TabContext } from "@contexts/auth/domain";
import { ILoginUserResponseDTO } from "../../dto"; import { ILoginUserResponseDTO } from "../../dto";
export interface ILoginPresenter { export interface ILoginPresenter {
map: (data: { map: (data: {
user: AuthenticatedUser; user: AuthenticatedUser;
tabContext: TabContext;
tokens: { tokens: {
accessToken: string; accessToken: string;
refreshToken: string; refreshToken: string;
@ -14,6 +15,7 @@ export interface ILoginPresenter {
export const LoginPresenter: ILoginPresenter = { export const LoginPresenter: ILoginPresenter = {
map: (data: { map: (data: {
user: AuthenticatedUser; user: AuthenticatedUser;
tabContext: TabContext;
tokens: { tokens: {
accessToken: string; accessToken: string;
refreshToken: string; refreshToken: string;
@ -21,16 +23,20 @@ export const LoginPresenter: ILoginPresenter = {
}): ILoginUserResponseDTO => { }): ILoginUserResponseDTO => {
const { const {
user, user,
tabContext,
tokens: { accessToken, refreshToken }, tokens: { accessToken, refreshToken },
} = data; } = data;
const userData = user.toPersistenceData(); const userData = user.toPersistenceData();
const tabContextData = tabContext.toPersistenceData();
return { return {
user: { user: {
id: userData.id, id: userData.id,
email: userData.email, email: userData.email,
username: userData.username, username: userData.username,
tab_id: tabContextData.tab_id,
}, },
tokens: { tokens: {
access_token: accessToken, access_token: accessToken,

View File

@ -8,7 +8,3 @@ export interface ILoginUserRequestDTO {
email: string; email: string;
password: string; password: string;
} }
export interface ISelectCompanyRequestDTO {
companyId: string;
}

View File

@ -9,6 +9,7 @@ export interface ILoginUserResponseDTO {
id: string; id: string;
username: string; username: string;
email: string; email: string;
tab_id: string;
}; };
tokens: { tokens: {
access_token: string; access_token: string;
@ -17,6 +18,4 @@ export interface ILoginUserResponseDTO {
//tab_id: string; //tab_id: string;
} }
export interface ILogoutResponseDTO { export interface ILogoutResponseDTO {}
message: string;
}

View File

@ -2,19 +2,16 @@ import { UniqueID } from "@common/domain";
import { ApiError, ExpressController } from "@common/presentation"; import { ApiError, ExpressController } from "@common/presentation";
import { AuthenticatedUser } from "@contexts/auth/domain"; import { AuthenticatedUser } from "@contexts/auth/domain";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import passport from "passport";
// Extender el Request de Express para incluir el usuario autenticado optionalmente // Extender el Request de Express para incluir el usuario autenticado optionalmente
interface AuthenticatedRequest extends Request { interface AuthenticatedRequest extends Request {
user?: AuthenticatedUser; user?: AuthenticatedUser;
} }
// Middleware para autenticar usando passport con el local-jwt strategy
const _authenticateJwt = passport.authenticate("jwt", { session: false });
// Comprueba el rol del usuario // Comprueba el rol del usuario
const _authorizeUser = (condition: (user: AuthenticatedUser) => boolean) => { const _authorizeUser = (condition: (user: AuthenticatedUser) => boolean) => {
return (req: AuthenticatedRequest, res: Response, next: NextFunction) => { return (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
console.log(req.user);
const user = req.user as AuthenticatedUser; const user = req.user as AuthenticatedUser;
if (!user || !condition(user)) { if (!user || !condition(user)) {
return ExpressController.errorResponse( return ExpressController.errorResponse(
@ -32,15 +29,19 @@ const _authorizeUser = (condition: (user: AuthenticatedUser) => boolean) => {
}; };
}; };
// Middleware para autenticar usando passport con el local-jwt strategy
//export const authenticateJWT = [];
//export const validateUserRegister = [_authenticateEmail];
// Verifica que el usuario esté autenticado // Verifica que el usuario esté autenticado
export const validateUser = [_authenticateJwt, _authorizeUser((user) => user.isUser)]; export const authenticateUser = [_authorizeUser((user) => user.isUser)];
// Verifica que el usuario sea administrador // Verifica que el usuario sea administrador
export const validateUserIsAdmin = [_authenticateJwt, _authorizeUser((user) => user.isAdmin)]; export const authenticateUserIsAdmin = [_authorizeUser((user) => user.isAdmin)];
// Middleware para verificar que el usuario sea administrador o el dueño de los datos (self) // Middleware para verificar que el usuario sea administrador o el dueño de los datos (self)
export const validateUserIsAdminOrOwner = [ export const checkUserIsAdminOrOwner = [
_authenticateJwt,
(req: AuthenticatedRequest, res: Response, next: NextFunction) => { (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
const user = req.user as AuthenticatedUser; const user = req.user as AuthenticatedUser;
const { userId } = req.params; const { userId } = req.params;

View File

@ -1,6 +1,5 @@
import { UniqueID } from "@common/domain"; import { UniqueID } from "@common/domain";
import { ApiError, ExpressController } from "@common/presentation"; import { ApiError, ExpressController } from "@common/presentation";
import { createTabContextService } from "@contexts/auth/application";
import { TabContext } from "@contexts/auth/domain"; import { TabContext } from "@contexts/auth/domain";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import httpStatus from "http-status"; import httpStatus from "http-status";
@ -40,7 +39,7 @@ export const validateTabContextHeader = async (
res res
); );
} }
const contextOrError = await createTabContextService().getContextByTabId(tabIdOrError.data); /*const contextOrError = await createTabContextService().getContextByTabId(tabIdOrError.data);
if (contextOrError.isFailure) { if (contextOrError.isFailure) {
return ExpressController.errorResponse( return ExpressController.errorResponse(
new ApiError({ new ApiError({
@ -55,6 +54,6 @@ export const validateTabContextHeader = async (
const context = contextOrError.data; const context = contextOrError.data;
req.tabContext = context; req.tabContext = context;*/
next(); next();
}; };

View File

@ -1,5 +1,6 @@
import { validateRequest } from "@common/presentation"; import { validateRequestDTO } from "@common/presentation";
import { validateTabContextHeader, validateUser } from "@contexts/auth/presentation"; import { createAuthProvider } from "@contexts/auth/infraestructure";
import { validateTabContextHeader } from "@contexts/auth/presentation";
import { createLoginController } from "@contexts/auth/presentation/controllers"; import { createLoginController } from "@contexts/auth/presentation/controllers";
import { createLogoutController } from "@contexts/auth/presentation/controllers/logout/logout.controller"; import { createLogoutController } from "@contexts/auth/presentation/controllers/logout/logout.controller";
import { createRegisterController } from "@contexts/auth/presentation/controllers/register/register.controller"; import { createRegisterController } from "@contexts/auth/presentation/controllers/register/register.controller";
@ -8,6 +9,7 @@ import { NextFunction, Request, Response, Router } from "express";
export const authRouter = (appRouter: Router) => { export const authRouter = (appRouter: Router) => {
const authRoutes: Router = Router({ mergeParams: true }); const authRoutes: Router = Router({ mergeParams: true });
const authProvider = createAuthProvider();
/** /**
* @api {post} /api/auth/register Register a new user * @api {post} /api/auth/register Register a new user
@ -23,7 +25,7 @@ export const authRouter = (appRouter: Router) => {
* *
* @apiError (400) {String} message Error message. * @apiError (400) {String} message Error message.
*/ */
authRoutes.post("/register", validateRequest(RegisterUserSchema), (req, res, next) => { authRoutes.post("/register", validateRequestDTO(RegisterUserSchema), (req, res, next) => {
createRegisterController().execute(req, res, next); createRegisterController().execute(req, res, next);
}); });
@ -44,7 +46,7 @@ export const authRouter = (appRouter: Router) => {
*/ */
authRoutes.post( authRoutes.post(
"/login", "/login",
validateRequest(LoginUserSchema), validateRequestDTO(LoginUserSchema),
validateTabContextHeader, validateTabContextHeader,
(req: Request, res: Response, next: NextFunction) => { (req: Request, res: Response, next: NextFunction) => {
createLoginController().execute(req, res, next); createLoginController().execute(req, res, next);
@ -64,8 +66,8 @@ export const authRouter = (appRouter: Router) => {
*/ */
authRoutes.post( authRoutes.post(
"/logout", "/logout",
validateUser,
validateTabContextHeader, validateTabContextHeader,
authProvider.authenticateJWT(),
(req: Request, res: Response, next: NextFunction) => { (req: Request, res: Response, next: NextFunction) => {
createLogoutController().execute(req, res, next); createLogoutController().execute(req, res, next);
} }