.
This commit is contained in:
parent
bc6e4e594f
commit
eef6e6fa97
1
.gitignore
vendored
1
.gitignore
vendored
@ -38,6 +38,7 @@ error-*.log
|
||||
# Misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
*-audit.json
|
||||
|
||||
#Jetbrains
|
||||
.idea
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { logger } from "@common/infrastructure/logger";
|
||||
import { globalErrorHandler } from "@common/presentation";
|
||||
import { initializePassportAuthProvide } from "@contexts/auth/infraestructure";
|
||||
import { createAuthProvider } from "@contexts/auth/infraestructure";
|
||||
import dotenv from "dotenv";
|
||||
import express, { Application } from "express";
|
||||
import helmet from "helmet";
|
||||
@ -24,9 +24,9 @@ export function createApp(): Application {
|
||||
|
||||
app.use(responseTime()); // set up the response-time middleware
|
||||
|
||||
// Inicializar Passport
|
||||
// Inicializar Auth Provider
|
||||
app.use((req, res, next) => {
|
||||
initializePassportAuthProvide();
|
||||
createAuthProvider().initialize();
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
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 {
|
||||
generateAccessToken(payload: object): string;
|
||||
generateRefreshToken(payload: object): string;
|
||||
verifyToken(token: string): Promise<AuthenticatedUser | null>;
|
||||
generateAccessToken(payload: IJWTPayload): string;
|
||||
generateRefreshToken(payload: IJWTPayload): string;
|
||||
|
||||
registerUser(params: {
|
||||
username: Username;
|
||||
@ -20,6 +27,7 @@ export interface IAuthService {
|
||||
Result<
|
||||
{
|
||||
user: AuthenticatedUser;
|
||||
tabContext: TabContext;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
@ -31,8 +39,5 @@ export interface IAuthService {
|
||||
|
||||
logoutUser(params: { email: EmailAddress; tabId: UniqueID }): Promise<Result<void, Error>>;
|
||||
|
||||
verifyUser(params: {
|
||||
email: EmailAddress;
|
||||
plainPassword: PlainPassword;
|
||||
}): Promise<Result<AuthenticatedUser, Error>>;
|
||||
getUserByEmail(params: { email: EmailAddress }): Promise<Result<AuthenticatedUser, Error>>;
|
||||
}
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
import { Result, UniqueID } from "@common/domain";
|
||||
import { ITransactionManager } from "@common/infrastructure/database";
|
||||
import jwt from "jsonwebtoken";
|
||||
import {
|
||||
AuthenticatedUser,
|
||||
EmailAddress,
|
||||
HashPassword,
|
||||
IAuthenticatedUserRepository,
|
||||
PlainPassword,
|
||||
TabContext,
|
||||
Username,
|
||||
} from "../domain";
|
||||
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";
|
||||
|
||||
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";
|
||||
|
||||
@ -32,16 +31,12 @@ export class AuthService implements IAuthService {
|
||||
this._transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
generateAccessToken(payload: object): string {
|
||||
return jwt.sign(payload, SECRET_KEY, { expiresIn: ACCESS_EXPIRATION });
|
||||
generateAccessToken(payload: IJWTPayload): string {
|
||||
return JwtHelper.generateToken(payload, ACCESS_EXPIRATION);
|
||||
}
|
||||
|
||||
generateRefreshToken(payload: object): string {
|
||||
return jwt.sign(payload, SECRET_KEY, { expiresIn: REFRESH_EXPIRATION });
|
||||
}
|
||||
|
||||
verifyToken(token: string): any {
|
||||
return jwt.verify(token, SECRET_KEY);
|
||||
generateRefreshToken(payload: IJWTPayload): string {
|
||||
return JwtHelper.generateToken(payload, REFRESH_EXPIRATION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,6 +99,7 @@ export class AuthService implements IAuthService {
|
||||
Result<
|
||||
{
|
||||
user: AuthenticatedUser;
|
||||
tabContext: TabContext;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
@ -145,7 +141,9 @@ export class AuthService implements IAuthService {
|
||||
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
|
||||
const accessToken = this.generateAccessToken({
|
||||
@ -157,10 +155,14 @@ export class AuthService implements IAuthService {
|
||||
|
||||
const refreshToken = this.generateRefreshToken({
|
||||
userId: user.id.toString(),
|
||||
email: email.toString(),
|
||||
tabId: tabId.toString(),
|
||||
roles: ["USER"],
|
||||
});
|
||||
|
||||
return Result.ok({
|
||||
user,
|
||||
tabContext,
|
||||
tokens: {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
@ -213,27 +215,17 @@ export class AuthService implements IAuthService {
|
||||
}
|
||||
}
|
||||
|
||||
async verifyUser(params: {
|
||||
email: EmailAddress;
|
||||
plainPassword: PlainPassword;
|
||||
}): Promise<Result<AuthenticatedUser, Error>> {
|
||||
async getUserByEmail(params: { email: EmailAddress }): Promise<Result<AuthenticatedUser, Error>> {
|
||||
try {
|
||||
return await this._transactionManager.complete(async (transaction) => {
|
||||
const { email, plainPassword } = params;
|
||||
const { email } = params;
|
||||
const userResult = await this._userRepo.getUserByEmail(email, transaction);
|
||||
|
||||
if (userResult.isFailure || !userResult.data) {
|
||||
return Result.fail(new Error("Invalid email or password"));
|
||||
}
|
||||
|
||||
const user = userResult.data;
|
||||
const isValidPassword = await user.verifyPassword(plainPassword);
|
||||
|
||||
if (!isValidPassword) {
|
||||
return Result.fail(new Error("Invalid email or password"));
|
||||
}
|
||||
|
||||
return Result.ok(user);
|
||||
return Result.ok(userResult.data);
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
return Result.fail(error as Error);
|
||||
|
||||
@ -19,9 +19,9 @@ export interface IAuthenticatedUser {
|
||||
isUser: boolean;
|
||||
isAdmin: boolean;
|
||||
|
||||
contexts: ICollection<QuoteItem>;
|
||||
|
||||
verifyPassword(candidatePassword: PlainPassword): Promise<boolean>;
|
||||
hasRole(role: string): boolean;
|
||||
hasRoles(roles: string[]): boolean;
|
||||
getRoles(): string[];
|
||||
toPersistenceData(): any;
|
||||
}
|
||||
@ -43,10 +43,6 @@ export class AuthenticatedUser
|
||||
return Result.ok(user);
|
||||
}
|
||||
|
||||
private _hasRole(role: string): boolean {
|
||||
return (this._props.roles || []).some((r) => r === role);
|
||||
}
|
||||
|
||||
verifyPassword(candidatePassword: PlainPassword): Promise<boolean> {
|
||||
return this._props.hashPassword.verifyPassword(candidatePassword.toString());
|
||||
}
|
||||
@ -55,6 +51,14 @@ export class AuthenticatedUser
|
||||
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 {
|
||||
return this._props.username;
|
||||
}
|
||||
@ -64,11 +68,11 @@ export class AuthenticatedUser
|
||||
}
|
||||
|
||||
get isUser(): boolean {
|
||||
return this._hasRole("user");
|
||||
return this.hasRole("user");
|
||||
}
|
||||
|
||||
get isAdmin(): boolean {
|
||||
return this._hasRole("admin");
|
||||
return this.hasRole("admin");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
export * from "./jwt.helper";
|
||||
export * from "./mappers";
|
||||
export * from "./passport";
|
||||
export * from "./sequelize";
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { createAuthService } from "@contexts/auth/application";
|
||||
import { PassportAuthProvider } from "./passport-auth-provider";
|
||||
import { createAuthService, createTabContextService } from "../../application";
|
||||
import { IJWTPayload, PassportAuthProvider } from "./passport-auth-provider";
|
||||
|
||||
export const createPassportAuthProvider = () => {
|
||||
const _authService = createAuthService();
|
||||
return new PassportAuthProvider(_authService);
|
||||
};
|
||||
export { IJWTPayload };
|
||||
|
||||
export const initializePassportAuthProvide = () => createPassportAuthProvider();
|
||||
export const createAuthProvider = () =>
|
||||
new PassportAuthProvider(createAuthService(), createTabContextService());
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
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 {
|
||||
static generateToken(payload: object, expiresIn = "1h"): string {
|
||||
@ -1,4 +1,6 @@
|
||||
import { Result, UniqueID } from "@common/domain";
|
||||
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 passport from "passport";
|
||||
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";
|
||||
|
||||
export interface IJWTPayload {
|
||||
userId: string;
|
||||
email: string;
|
||||
tabId: string;
|
||||
roles: string[];
|
||||
}
|
||||
|
||||
export class PassportAuthProvider {
|
||||
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);
|
||||
if (emailVO.isFailure) return Promise.resolve(null);
|
||||
if (emailVO.isFailure) {
|
||||
return Result.fail(emailVO.error);
|
||||
}
|
||||
|
||||
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,
|
||||
plainPassword: plainPasswordVO.data,
|
||||
});
|
||||
|
||||
if (userResult.isFailure || !userResult.data) {
|
||||
return Promise.resolve(null);
|
||||
return Result.fail(new Error("Invalid email or password"));
|
||||
}
|
||||
|
||||
const user = userResult.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
|
||||
*/
|
||||
initializePassport(): void {
|
||||
initialize(): void {
|
||||
const jwtOptions = {
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: SECRET_KEY,
|
||||
@ -42,10 +109,12 @@ export class PassportAuthProvider {
|
||||
|
||||
passport.use(
|
||||
"jwt",
|
||||
new JwtStrategy(jwtOptions, (tokenPayload, done) => {
|
||||
new JwtStrategy(jwtOptions, async (tokenPayload, done) => {
|
||||
try {
|
||||
console.log(tokenPayload);
|
||||
return done(null, tokenPayload);
|
||||
const result = await this._getUserAndContextByToken(tokenPayload);
|
||||
return result.isSuccess
|
||||
? done(null, result)
|
||||
: done(result.error, false, { message: "Invalid JWT data" });
|
||||
} catch (error) {
|
||||
return done(error, false);
|
||||
}
|
||||
@ -58,7 +127,7 @@ export class PassportAuthProvider {
|
||||
{ usernameField: "email", passwordField: "password" },
|
||||
async (email, password, done) => {
|
||||
try {
|
||||
const user = await this._verifyUser(email, password);
|
||||
const user = await this._getUserByEmailAndPassword(email, password);
|
||||
return user
|
||||
? done(null, user)
|
||||
: done(null, false, { message: "Invalid email or password" });
|
||||
@ -72,8 +141,7 @@ export class PassportAuthProvider {
|
||||
passport.initialize();
|
||||
}
|
||||
|
||||
constructor(authService: IAuthService) {
|
||||
this._authService = authService;
|
||||
this.initializePassport();
|
||||
authenticateJWT() {
|
||||
return passport.authenticate("jwt", { session: false });
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,6 @@
|
||||
import {
|
||||
DataTypes,
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
Model,
|
||||
NonAttribute,
|
||||
Sequelize,
|
||||
} from "sequelize";
|
||||
import { TabContextCreationAttributes, TabContextModel } from "./tab-context.model";
|
||||
import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize";
|
||||
|
||||
export type AuthUserCreationAttributes = InferCreationAttributes<
|
||||
AuthUserModel,
|
||||
{ omit: "contexts" }
|
||||
> & {
|
||||
contexts: TabContextCreationAttributes[];
|
||||
};
|
||||
export type AuthUserCreationAttributes = InferCreationAttributes<AuthUserModel>;
|
||||
|
||||
export class AuthUserModel extends Model<
|
||||
InferAttributes<AuthUserModel>,
|
||||
@ -24,22 +11,11 @@ export class AuthUserModel extends Model<
|
||||
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 username: string;
|
||||
declare email: string;
|
||||
declare hash_password: string;
|
||||
declare roles: string[];
|
||||
|
||||
declare contexts: NonAttribute<TabContextModel[]>;
|
||||
}
|
||||
|
||||
export default (sequelize: Sequelize) => {
|
||||
|
||||
@ -1,21 +1,10 @@
|
||||
import {
|
||||
DataTypes,
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
Model,
|
||||
NonAttribute,
|
||||
Sequelize,
|
||||
} from "sequelize";
|
||||
import { AuthUserModel } from "./auth-user.model";
|
||||
import { DataTypes, InferAttributes, InferCreationAttributes, Model, Sequelize } from "sequelize";
|
||||
|
||||
export type TabContextCreationAttributes = InferCreationAttributes<
|
||||
TabContextModel,
|
||||
{ omit: "user" }
|
||||
>;
|
||||
export type TabContextCreationAttributes = InferCreationAttributes<TabContextModel>;
|
||||
|
||||
export class TabContextModel extends Model<
|
||||
InferAttributes<TabContextModel, { omit: "user" }>,
|
||||
InferCreationAttributes<TabContextModel, { omit: "user" }>
|
||||
InferAttributes<TabContextModel>,
|
||||
InferCreationAttributes<TabContextModel>
|
||||
> {
|
||||
// To avoid table creation
|
||||
/*static async sync(): Promise<any> {
|
||||
@ -23,21 +12,11 @@ export class TabContextModel extends Model<
|
||||
}*/
|
||||
static associate(connection: Sequelize) {
|
||||
const { AuthUserModel } = connection.models;
|
||||
|
||||
TabContextModel.belongsTo(AuthUserModel, {
|
||||
as: "user",
|
||||
foreignKey: "user_id",
|
||||
onDelete: "CASCADE",
|
||||
});
|
||||
}
|
||||
|
||||
declare id: string;
|
||||
declare tab_id: string;
|
||||
declare user_id: string;
|
||||
declare company_id: string;
|
||||
declare branch_id: string;
|
||||
|
||||
declare user: NonAttribute<AuthUserModel>;
|
||||
}
|
||||
|
||||
export default (sequelize: Sequelize) => {
|
||||
@ -55,14 +34,6 @@ export default (sequelize: Sequelize) => {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
},
|
||||
company_id: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
},
|
||||
branch_id: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
|
||||
@ -26,17 +26,17 @@ class LoginController extends ExpressController {
|
||||
return this.clientError("Invalid input data", resultValidation.error);
|
||||
}
|
||||
|
||||
const userOrError = await this._authService.loginUser({
|
||||
const loginResultOrError = await this._authService.loginUser({
|
||||
email: emailVO.data,
|
||||
plainPassword: plainPasswordVO.data,
|
||||
tabId: tabIdVO.data,
|
||||
});
|
||||
|
||||
if (userOrError.isFailure) {
|
||||
return this.unauthorizedError(userOrError.error.message);
|
||||
if (loginResultOrError.isFailure) {
|
||||
return this.unauthorizedError(loginResultOrError.error.message);
|
||||
}
|
||||
|
||||
return this.created(this._presenter.map(userOrError.data));
|
||||
return this.created(this._presenter.map(loginResultOrError.data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { AuthenticatedUser } from "@contexts/auth/domain";
|
||||
import { AuthenticatedUser, TabContext } from "@contexts/auth/domain";
|
||||
import { ILoginUserResponseDTO } from "../../dto";
|
||||
|
||||
export interface ILoginPresenter {
|
||||
map: (data: {
|
||||
user: AuthenticatedUser;
|
||||
tabContext: TabContext;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
@ -14,6 +15,7 @@ export interface ILoginPresenter {
|
||||
export const LoginPresenter: ILoginPresenter = {
|
||||
map: (data: {
|
||||
user: AuthenticatedUser;
|
||||
tabContext: TabContext;
|
||||
tokens: {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
@ -21,16 +23,20 @@ export const LoginPresenter: ILoginPresenter = {
|
||||
}): ILoginUserResponseDTO => {
|
||||
const {
|
||||
user,
|
||||
tabContext,
|
||||
tokens: { accessToken, refreshToken },
|
||||
} = data;
|
||||
|
||||
const userData = user.toPersistenceData();
|
||||
|
||||
const tabContextData = tabContext.toPersistenceData();
|
||||
|
||||
return {
|
||||
user: {
|
||||
id: userData.id,
|
||||
email: userData.email,
|
||||
username: userData.username,
|
||||
tab_id: tabContextData.tab_id,
|
||||
},
|
||||
tokens: {
|
||||
access_token: accessToken,
|
||||
|
||||
@ -8,7 +8,3 @@ export interface ILoginUserRequestDTO {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface ISelectCompanyRequestDTO {
|
||||
companyId: string;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ export interface ILoginUserResponseDTO {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
tab_id: string;
|
||||
};
|
||||
tokens: {
|
||||
access_token: string;
|
||||
@ -17,6 +18,4 @@ export interface ILoginUserResponseDTO {
|
||||
//tab_id: string;
|
||||
}
|
||||
|
||||
export interface ILogoutResponseDTO {
|
||||
message: string;
|
||||
}
|
||||
export interface ILogoutResponseDTO {}
|
||||
|
||||
@ -2,19 +2,16 @@ import { UniqueID } from "@common/domain";
|
||||
import { ApiError, ExpressController } from "@common/presentation";
|
||||
import { AuthenticatedUser } from "@contexts/auth/domain";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import passport from "passport";
|
||||
|
||||
// Extender el Request de Express para incluir el usuario autenticado optionalmente
|
||||
interface AuthenticatedRequest extends Request {
|
||||
user?: AuthenticatedUser;
|
||||
}
|
||||
|
||||
// Middleware para autenticar usando passport con el local-jwt strategy
|
||||
const _authenticateJwt = passport.authenticate("jwt", { session: false });
|
||||
|
||||
// Comprueba el rol del usuario
|
||||
const _authorizeUser = (condition: (user: AuthenticatedUser) => boolean) => {
|
||||
return (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
|
||||
console.log(req.user);
|
||||
const user = req.user as AuthenticatedUser;
|
||||
if (!user || !condition(user)) {
|
||||
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
|
||||
export const validateUser = [_authenticateJwt, _authorizeUser((user) => user.isUser)];
|
||||
export const authenticateUser = [_authorizeUser((user) => user.isUser)];
|
||||
|
||||
// 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)
|
||||
export const validateUserIsAdminOrOwner = [
|
||||
_authenticateJwt,
|
||||
export const checkUserIsAdminOrOwner = [
|
||||
(req: AuthenticatedRequest, res: Response, next: NextFunction) => {
|
||||
const user = req.user as AuthenticatedUser;
|
||||
const { userId } = req.params;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { UniqueID } from "@common/domain";
|
||||
import { ApiError, ExpressController } from "@common/presentation";
|
||||
import { createTabContextService } from "@contexts/auth/application";
|
||||
import { TabContext } from "@contexts/auth/domain";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import httpStatus from "http-status";
|
||||
@ -40,7 +39,7 @@ export const validateTabContextHeader = async (
|
||||
res
|
||||
);
|
||||
}
|
||||
const contextOrError = await createTabContextService().getContextByTabId(tabIdOrError.data);
|
||||
/*const contextOrError = await createTabContextService().getContextByTabId(tabIdOrError.data);
|
||||
if (contextOrError.isFailure) {
|
||||
return ExpressController.errorResponse(
|
||||
new ApiError({
|
||||
@ -55,6 +54,6 @@ export const validateTabContextHeader = async (
|
||||
|
||||
const context = contextOrError.data;
|
||||
|
||||
req.tabContext = context;
|
||||
req.tabContext = context;*/
|
||||
next();
|
||||
};
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { validateRequest } from "@common/presentation";
|
||||
import { validateTabContextHeader, validateUser } from "@contexts/auth/presentation";
|
||||
import { validateRequestDTO } from "@common/presentation";
|
||||
import { createAuthProvider } from "@contexts/auth/infraestructure";
|
||||
import { validateTabContextHeader } from "@contexts/auth/presentation";
|
||||
import { createLoginController } from "@contexts/auth/presentation/controllers";
|
||||
import { createLogoutController } from "@contexts/auth/presentation/controllers/logout/logout.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) => {
|
||||
const authRoutes: Router = Router({ mergeParams: true });
|
||||
const authProvider = createAuthProvider();
|
||||
|
||||
/**
|
||||
* @api {post} /api/auth/register Register a new user
|
||||
@ -23,7 +25,7 @@ export const authRouter = (appRouter: Router) => {
|
||||
*
|
||||
* @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);
|
||||
});
|
||||
|
||||
@ -44,7 +46,7 @@ export const authRouter = (appRouter: Router) => {
|
||||
*/
|
||||
authRoutes.post(
|
||||
"/login",
|
||||
validateRequest(LoginUserSchema),
|
||||
validateRequestDTO(LoginUserSchema),
|
||||
validateTabContextHeader,
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
createLoginController().execute(req, res, next);
|
||||
@ -64,8 +66,8 @@ export const authRouter = (appRouter: Router) => {
|
||||
*/
|
||||
authRoutes.post(
|
||||
"/logout",
|
||||
validateUser,
|
||||
validateTabContextHeader,
|
||||
authProvider.authenticateJWT(),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
createLogoutController().execute(req, res, next);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user