简体   繁体   中英

NestJS passing Authorization header to HttpService

I have a NestJS application which acts as a proxy between a front-end and multiple other back-ends.

I basically want to be able to pass a specific header (Authorization) from incoming @Req (requests) in the controller to the HttpService that then talks to the other back-ends.

user controller (has access to request) -> user service (injects httpService that somehow already picks the Authorization header) -> External backends.

Right now I need to extract the token from @Headers and then pass token to service which has to paste it to all HttpService calls.

Thanks in advance!

Ok, I managed to solve this by actually using a middleware that I initially thought. I am not a 100% sure this is the NEST way but intercepting the underlying axios reference of the HttpService did the trick:

@Injectable()
export class BearerMiddleware implements NestMiddleware {
  constructor(private readonly httpService: HttpService) {}
  use(req: Request, res: Response, next: Function) {
    this.httpService.axiosRef.interceptors.request.use(request => {
      request.headers = {
        ...request.headers,
        Authorization: req.headers.Authorization || '',
      };
      return request;
    });
    next();
  }
}

I'm not sure if this will help you, but maybe if you get the header from the controller and put it in your services function...

// Controller:

@Get()
getAll(@Request() req){
    const header = req.headers;
    return this._zoneService.sendToHttp(header);
}

Maybe microservices can be better?

Besides the middleware answer, I have another version using interceptor :

@Injectable()
export class HttpServiceInterceptor implements NestInterceptor {
  constructor(private httpService: HttpService) {}
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
  
    // ** if you user normal HTTP module **
    const ctx = context.switchToHttp();
    const token = ctx.getRequest().headers['authorization'];

    // ** if you user GraphQL module **
    const ctx = GqlExecutionContext.create(context);
    const token = ctx.getContext().token;

    if (ctx.token) {
      this.httpService.axiosRef.defaults.headers.common['authorization'] =
        token;
    }
    return next.handle().pipe();
  }
}

If you use GraphQLModule , do not forget to pass token to context:

GraphQLModule.forRoot({
  debug: true,
  playground: true,
  autoSchemaFile: 'schema.gql',
  context: ({ req }) => {
    return { token: req.headers.authorization };
  },
}),

Every preparation work is ready, let's use interceptors

The interceptor can be injected into a certain controller:

@UseInterceptors(HttpServiceInterceptor)
export class CatsController {}

or register a global interceptor like following:

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: HttpServiceInterceptor,
    },
  ],
})
export class AppModule {}

Required import HttpModule into your module

import { HttpModule } from '@nestjs/axios';
@Module({
  providers: [],
  controllers: [YourController],
  imports: [
    HttpModule,
  ],
  exports: [],
})
export class YourModule {}

In your controller

import { HttpService } from '@nestjs/axios';
import { Controller, HttpStatus, Res, BadRequestException } from '@nestjs/common';

@Controller('your-controller')
export class YourController {
  constructor(
    private httpService: HttpService,
  ) {}

  async fetchApi(@Res() res) {
    const urlAPI = 'https://xxx.vn';
    try {
      const source = await this.httpService.get(urlAPI,
        {
          headers: { Authorization: 'Basic XXX-TOKEN' },
        },
      );
      return res.status(HttpStatus.OK).json({ ...source });
    } catch (error) {
      throw new BadRequestException(error.response?.statusText);
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM