inversify/inversify-express-utils

Passing additional data to Middleware

josezone opened this issue · 2 comments

I am using

  • inversify 5.0.1
  • inversify-binding-decorators 4.0.0
  • inversify-express-utils 6.3.2
    The code I am working on can be seen at this Link
    The Problem
    I need to pass an additional parameter to the Middleware so that it will act as a factory,
    Example, I need to pass a role onto a middleware so that the system can check if the user has permission to access the API
    an example we need to create a middleware as follows
@provide("roles")
class RoleValidator extends BaseMiddleware {
    role(role){
        return handler(req: Request, res: Response, next: NextFunction) {
            if(req.user.role === role){
                next();
            } else {
                res.end();
            }
        }
    }
}

And the middleware is called by a controller

@controller('/test')
class UserController extends BaseHttpController {
    @httpPost('/', "roles=>'currentRole'")
    private test(
        @requestParam('param') param: string,
        res: Response,
        next: NextFunction
      ){
        //code
      }
}

How can this be achieved, this is a common scenario, that has to be used. Is it that, the feature is not supported.

You can implement it like this:

  1. Pass functions to endpoint decorator
    @httpPost('/', authenticateToken(), authorizeUser(['administrator']))

  2. Function example

export const authenticateToken = (/* PARAMS HERE */) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    const authHeader = req.headers.authorization;
    const token = authHeader && authHeader.split(' ')[1];

    if (!token) {
      return next(new AppError(HttpStatusCode.UNAUTHORIZED, 'error', 'No token'));
    }

    verify(token, process.env.ACCESS_TOKEN_SECRET, (error, user) => {
      if (error) {
        console.error(error);
        next(new AppError(HttpStatusCode.FORBIDDEN, 'error', 'Invalid or expired token'));
      }

      req.body.user = user?.user as IJwtUserPayload;
      next();
    });
  };
};

You can implement it like this:

  1. Pass functions to endpoint decorator
    @httpPost('/', authenticateToken(), authorizeUser(['administrator']))
  2. Function example
export const authenticateToken = (/* PARAMS HERE */) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    const authHeader = req.headers.authorization;
    const token = authHeader && authHeader.split(' ')[1];

    if (!token) {
      return next(new AppError(HttpStatusCode.UNAUTHORIZED, 'error', 'No token'));
    }

    verify(token, process.env.ACCESS_TOKEN_SECRET, (error, user) => {
      if (error) {
        console.error(error);
        next(new AppError(HttpStatusCode.FORBIDDEN, 'error', 'Invalid or expired token'));
      }

      req.body.user = user?.user as IJwtUserPayload;
      next();
    });
  };
};

I don't think it's possible with BaseMiddleware, so that you have access to http context, right?