ログイン検証情報はNextJos Passportなしで入手可能


この文章はNest Docs Authenticationの基礎の上で書くことを学びました.
OverviewsAuthenticationほとんどのアプリケーションで必要です.直接認証/認証は実施できますが、nest.jspassportでは容易に実施できます.
@nestjs/passportライブラリはpassportおよびnest.jsの移植モジュールである.
この記事では、Passportを使用して認証を実施する方法と、Customを使用して認証を実施する方法について説明します.
Passportpassportは、次の一連の機能を提供します.
|認証は
  • ユーザcredentialsによって決定される.
  • 認証トークンを発行するか、セッションと同じリポジトリにステータスを保持および管理できます.
  • credentialsでは、他の情報をリクエストに貼り付けることができます.(userId等)
  • 認証ユーザ情報の取得
    本明細書を読むと、passportの様々なstrategy(localjwtなど)を使用してcredentialsを検証し、CurrentUserを使用してユーザ情報を取得することができる.
    次のコードを見てみましょう.
    パスポートの使用
    まず、jwtを使用して、次のライブラリをインストールします.
    $ npm install --save @nestjs/passport passport @nestjs/jwt passport-jwt
    $ npm install --save-dev @types/passport-jwt
    次に、AuthModuleJwtModuleに追加する.
    import { PassportModule } from '@nestjs/passport';
    import { JwtModule } from '@nestjs/jwt';
    
    @Module({
      imports: [
        UsersModule,
        PassportModule,
        JwtModule.register({
          secret: 'SECRET',
          signOptions: { expiresIn: '60s' },
        }),
      ],
      providers: [AuthService],
      exports: [AuthService],
    })
    export class AuthModule {}
    次に、RequestJwtタグを受信した後、Decodeの値をDecodeに貼り付ける方法を設定する必要があります.
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor() {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // 헤더 Bearer 토큰을 파싱합니다.
          ignoreExpiration: false, // 만료된 토큰이라면 에러를 반환합니다.
          secretOrKey: 'SECRET',
        })
      }
    
      async validate(payload: any) {
        // 이 데이터가 req.user로 접근할 수 있게 합니다.
        return { userId: payload.sub, username: payload.username }
      }
    }
    次に、RequestJwtStrategyに追加します.
    import { PassportModule } from '@nestjs/passport';
    import { JwtModule } from '@nestjs/jwt';
    
    @Module({
      imports: [
        UsersModule,
        PassportModule,
        JwtModule.register({
          secret: 'SECRET',
          signOptions: { expiresIn: '60s' },
        }),
      ],
      providers: [AuthService, JwtStrategy],
      exports: [AuthService],
    })
    export class AuthModule {}
    使用可能なAuthModuleユーザーデータをUseGuardsDecoratorからインポートできます.
    @Controller()
    export class AppController {
      constructor(private authService: AuthService) {}
    
      @UseGuards(LocalAuthGuard)
      @Post('auth/login')
      async login(@Request() req) {
        return this.authService.login(req.user);
      }
    
      // JwtStrategy를 통해 credentials를 해독합니다.
      // 만일 토큰이 유효하지 않다면 에러를 반환합니다.
      @UseGuards(AuthGuard('jwt'))
      @Get('profile')
      getProfile(@Request() req) {
        return req.user; // Decode된 유저 정보는 req.user에 있습니다.
      }
    }
    ここでは、正式なドキュメントの内容を抜粋します.詳細については、文書を参照してください.
    ただ問題があるだけです.ユーザーがログインまたは非ログインAPIを使用する必要がある場合は、処理が困難です.
    例を挙げます.
    商品詳細ページをCummersに表示します.詳細ページには商品の良さが表示されます.ログインユーザインタフェースDecode,良いかどうか、非ログインユーザインタフェース無条件jwt.

    コントローラのコードは大体次のようになっているかもしれません.
    @Controller()
    export class ProductsController {
      constructor(private productsService: ProductsService) {}
    
      @Get(':id')
      getProfile(@Request() req, @Param('id', ParseIntPipe) productId: number) {
        const product = await this.productsService.findOneByProductId(productId)
        const user = req.user
    
        // 비로그인이면 false, 로그인이면 좋아요 여부 체크
        const isLike = !!user ? await this.productsService.checkIsLikeProduct(user.id, productId) : false
        return { ...product, isLike }
      }
    }
    しかし、このコードには問題があります.ユーザー情報(Service)を取得するには、falsereq.userControllerデコーダがあることを確認します.
    したがって、methodアプリケーションUseGuardsにより、UseGuardsインポートAuthGuard('jwt')情報が実行される.
    パスポートの無効化
    そこで、パスポートを使用せずに認証する方法を見てみましょう.
    従来のJwtStrategyは、最終的にはreq.userまたはnest.jsUseGuardsInterceptorPipeおよびControllerである.
    各ミドルウェアに名前を付けて、開発者がビジネスロジックを区別し、使いやすいようにします.

    このフローチャートを参照して、Serviceを含む他のミドルウェアを使用して、上記の問題を解決します.
    まず、問題を解決するには、Middleware-にユーザー情報を貼り付け、ログインするかどうかを確認する必要があります.UseGuardsのように、ログインの有無を確認した後、Requestにユーザ情報を貼り付けるのではなく、passportにユーザ情報を貼り付けてからログイン情報を確認します.
    このためには、Requestより前に実行されたRequestセクションで要求に情報を追加する必要がある.
    import { Injectable, NestMiddleware } from '@nestjs/common'
    import { Request, Response } from 'express'
    import { verifyToken } from './auth.jwt.util'
    
    @Injectable()
    export class AuthTokenMiddleware implements NestMiddleware {
      // token을 decode후 req.user에 붙여서 넘어갑니다.
      // 만약 토큰이 없거나 유효하지 않으면 req.user에는 null 값이 들어갑니다.
      public async use(req: Request, res: Response, next: () => void) {
        req.user = await this.verifyUser(req)
        return next()
      }
    
      private async verifyUser(req: Request): Promise<number> {
        let user: User = null
        try {
          const { authorization } = req.headers
          const token = authorization.replace('Bearer ', '').replace('bearer ', '')
          const decoded = await verifyToken(token)
          user = decoded
        } catch (e) {}
    
        return user
      }
    }
    上記のミドルウェアを作成した後、すべてのルーティングがミドルウェアを通過していることを確認します.
    export class AppModule {
      configure(consumer: MiddlewareConsumer) {
        consumer.apply(AuthTokenMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL })
      }
    }
    これにより、Guardにかかわらず、すべてのルーティングがmiddlewareにアクセスできるようになりました.以上の商品照会APIコードは正常に動作しています.
    その後、UseGuardsを使用すると、非ログインユーザはブロックロジックを作成します.
    import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'
    import { Reflector } from '@nestjs/core'
    
    
    @Injectable()
    export class AuthGuard implements CanActivate {
      constructor(private readonly reflector: Reflector) {}
      public canActivate(context: ExecutionContext): boolean {
        const req = context.switchToHttp().getRequest()
        if (!req.user) throw new UnauthorizedException('권한이 없습니다')
        return true
      }
    }
    ミドルウェアでは、まず情報をパケット化し、req.user論理を簡略化する.
    References
  • https://docs.nestjs.com/security/authentication