簡體   English   中英

在 nest.js 中,是否可以在參數裝飾器中獲取服務實例?

[英]In nest.js, is it possible to get service instance inside a param decorator?

我想使用 nest.js 來實現這樣的東西:(與 Spring 框架非常相似)

@Controller('/test')
class TestController {
  @Get()
  get(@Principal() principal: Principal) {

  }
}

在閱讀了幾個小時的文檔后,我發現 nest.js 支持創建自定義裝飾器。 所以我決定實現我自己的@Principal裝飾器。 裝飾器負責從 http 標頭中檢索訪問令牌,並使用令牌從我自己的身份驗證服務中獲取用戶的主體。

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

export const Principal = createParamDecorator((data: string, req) => {
  const bearerToken = req.header.Authorization;
  // parse.. and call my authService..
  // how to call my authService here?
  return null;
});

但問題是我不知道如何在裝飾器處理程序中獲取我的服務實例。 是否可以? 如何? 先感謝您

無法將服務注入您的自定義裝飾器。

相反,您可以創建一個AuthGuard訪問您的服務的AuthGuard 然后守衛可以向request對象添加一個屬性,然后您可以使用自定義裝飾器訪問該屬性:

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const bearerToken = request.header.Authorization;
    const user = await this.authService.authenticate(bearerToken);
    request.principal = user;
    // If you want to allow the request even if auth fails, always return true
    return !!user;
  }
}
import { createParamDecorator } from '@nestjs/common';

export const Principal = createParamDecorator((data: string, req) => {
  return req.principal;
});

然后在您的控制器中:

@Get()
@UseGuards(AuthGuard)
get(@Principal() principal: Principal) {
  // ...
}

請注意,nest 提供了一些用於身份驗證的標准模塊,請參閱文檔

您可以對所有控制器使用中間件。

auth.middleware.ts


interface AccountData {
  accId: string;
  iat: number;
  exp: number;
}

interface RequestWithAccountId extends Request {
  accId: string;
}

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  constructor(private readonly authenticationService: AuthenticationService) {}
  async use(req: RequestWithAccountId, res: Response, next: NextFunction) {
    const token =
      req.body.token || req.query.token || req.headers['authorization'];
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      const {
        accId,
      }: AccountData = await this.authenticationService.verifyToken(token);
      req.accId = accId;
      next();
    } catch (err) {
      throw new UnauthorizedException();
    }
  }
}

然后創建 AccountId 裝飾器

account-id.decorator.ts

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

export const AccountId = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const req = ctx.switchToHttp().getRequest();
    const token = req.accId;
    if (!token) {
      throw new UnauthorizedException();
    }
    return token;
  },
);

然后在您的控制器中應用 AccountId 裝飾器

your.controller.ts

  @Get()
  async someEndpoint(
    @AccountId() accountId,
  ) {
    console.log('accountId',accontId)
  }

NestJS v7

創建自定義管道

// parse-token.pipe.ts
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class ParseTokenPipe implements PipeTransform {
    // inject any dependency
    constructor(private authService: AuthService) {}
    
    async transform(value: any, metadata: ArgumentMetadata) {
        console.log('additional options', metadata.data);
        return this.authService.parse(value);
    }
}

將此管道與屬性裝飾器一起使用

// decorators.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { ParseTokenPipe} from './parse-token.pipe';

export const GetToken = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
  return ctx.switchToHttp().getRequest().header.Authorization;
});

export const Principal = (additionalOptions?: any) => GetToken(additionalOptions, ParseTokenPipe);

使用此裝飾器有或沒有其他選項

@Controller('/test')
class TestController {
  @Get()
  get(@Principal({hello: "world"}) principal) {}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM