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:
use
@Req()
in the controller and pass it, as you have mentionedMake 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.