最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to get req.user in services? - Stack Overflow

programmeradmin8浏览0评论

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!

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!

Share Improve this question asked Sep 24, 2021 at 15:00 markWankamarkWanka 7943 gold badges21 silver badges39 bronze badges 2
  • 1 Good question. That is why the Decorators are used. Have a look at my answer. – CyberEternal Commented Sep 24, 2021 at 19:51
  • any luck of finding the solution? – nmDat Commented Mar 10, 2023 at 7:01
Add a ment  | 

4 Answers 4

Reset to default 2

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.

Alternative solution(if you won't use request scoped injection): you can use async hooks. There is many libraries which simplify async hooks usage, like this one. You simply set your context in middleware:

@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;

            Context.run(next, { user: req.user });
        } else {
            throw new UnathorizedException();
        }
    }
}

And then you can get user instance in any place in your code by simply calling Context.get()

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

current-user.decorator.ts

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

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.

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.

发布评论

评论列表(0)

  1. 暂无评论