Home > Mobile >  How to get req.user in services?
How to get req.user in services?

Time:09-25

I create an authentication middleware in NestJs like below:

@Injectable()
export class AuthenticationMiddleware implements NestMiddleware {
    constructor() {}

    async use(req: any, res: any, next: () => void) {        
        const authHeaders = req.headers.authorization;
        
        if (authHeaders) {

            //some logic etc.
            //req.user = user;

            next();
        } else {
            throw new UnathorizedException();
        }
    }
}

... where I get from headers - an auth token, decode it and check if this user is correct and exists in database, if he exists then i set user object into req.user. And now I have a question, how to get this req.user in my services and use in business logic? I need to get id from req.user but I do not know how.

I know that I can do this by using @Req() request in controller parameters and pass this request into my function, but I do not want it, cause is (for me) a ugly practice. So, how to get this req.user into my services?

thanks for any help!

CodePudding user response:

Well, to get the user in the service you have two options:

  1. use @Req() in the controller and pass it, as you have mentioned

  2. Make your service REQUEST scoped and inject the request object into the service

Personally, I'd go with the former, as request scoping has its own pros and cons to start weighing and dealing with (like not being able to use the service in a passport strategy or a cron job). You can also just make the user optional, or bundle it into the body or whatever is passed to the service and then have access to it without it being an explicit parameter.

CodePudding user response:

You can define your own Request interface like this

import { Request } from 'express';
...

export interface IRequestWithUser extends Request {
  user: User;
}

then just give the type of req parameter to IRequestWithUser.

CodePudding user response:

You can create a decorator to do it. Something like this

current-user.decorator.ts

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CurrentUser = createParamDecorator(
  (property: string, ectx: ExecutionContext) => {
    const ctx = ectx.getArgByIndex(1);
    return property ? ctx.req.user && ctx.req.user[property] : ctx.req.user;
  },
);

example.controller.ts

@ApiTags('example')
@Controller('example')
export class ExampleController {
    constructor(private readonly exampleService: ExampleService) {}

    @Get('/')
    public async doSomething(@CurrentUser() user: YourUserClassOrInteface,): Promise<any> {
        return this.exampleService.exampleFunction(user.id);
    }
}

example.service.ts


export class ExampleService {
    constructor() {}

    public async exampleFunction(id: string): Promise<void> {
        console.log('id:', id);
        return;
    }
}

IMPORTANT: Injecting the Request in the services is not a good solution because it will make a new one in each endpoint request. That is why the Decorators are used. It will make it easy to work with needed data and do not hand over only the parameters that are needed instead of transferring the extra big request object.

  • Related