iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 25
0
Modern Web

讀官網文件邊走邊學nest.js系列 第 25

Day25 JSON Web Token(JWT)保護API Endpoint-使用Passport

今天要來練習使用JWT來保護API Enpoint

流程大致為:

  1. 安裝套件
  2. 取得token
  3. 新增jwtStrategy
  4. 設定defaultStrategy
  5. 測試

安裝套件

 
yarn add @nestjs/jwt passport-jwt @types/passport-jwt

其中@nestjs/jwt是個工具套件,結合nestjs Module設定概念和jsonwebtoken套件,可以少一點coding~~(但不是太多)~~

如何產生token

我們需要建立auth controller,

@Controller('auth')
export class AuthController {
    constructor(private readonly authService: AuthService){}
    // 傳入email及password取得jwt token
    @Post('getToken')
    getTokenByUserId(
        @Body('email') email: string,
        @Body('password') password: string,
        ){
        
        return this.authService.createToken(email, password);
        
    }
}

改寫auth service

@Injectable()
export class AuthService {
  constructor(
      // 注入機UsersService,所以需要import UsersModule
      // 底下的provider才能被注入
      private readonly usersService: UsersService,
      // nestjs提供的jsonwebtoken wrapper
      private readonly jwtService: JwtService,
  ) {}

  async createToken(email:string, password:string){
      
      // 驗證使用者,用最簡單舉例
      if(email !== password){
        throw new UnauthorizedException();
      }
      
      const user = {email}; // jwt decoded後會得到的資訊
      const expiration = 60*60;
      // sign回傳加密後的token
      const accessToken = this.jwtService.sign(user,{
        // 關於建立token時相關參數
        // 過期時間
        expiresIn:expiration,
        //issuer:'http://iron-nest.org',
        //algorithm:'RS256', // default是HMAC SHA256,也可以指定別的
        
      })
      return {
        expiration,
        accessToken
      };
      
  }

  async validateUser(payload) {
    // jwt decoded後會得到上面的user object
    return await this.usersService.findOneByEmail(payload.email);
  }
}

新增findOneByEmail於user service

 async findOneByEmail(email) {
        
    return await this.em.createQueryBuilder(User, 'u')
               .leftJoinAndSelect('u.roles', 'r')
               .where('u.email = :email', {email})
               .getOne();

 }

如何驗證token

驗證token需要用到passport-jwt套件,裡面已經幫我們寫好如何驗證,我們只要知道怎麼用就可以了

jwtStrategy,大致跟http-bearer一樣,不同的是super()要傳入

  • token
  • 相關資訊,key、issuer等
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(private readonly authService: AuthService) {
        super({
            // 這裡沒有intellisense可以用,下面這一段是說
            // 要從header取得bearer token
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 
            // 這裡的key就是要跟create token時的key一樣
            secretOrKey: 'iron-nest',
            issuer:'http://iron-nest.org'
        });
    }
    
    // Passport會自動verify jwt,如果key不正確,或是相關資訊
    // 不正確,如issuer
    async validate(payload){
        const user = await this.authService.validateUser(payload);
        if(!user) throw new UnauthorizedException();
        return user
    }
    
}

接著到auth module更新imports、controllers、providers

@Module({
    imports: [
        // 建立jsonwebtoken時的相關資訊
        JwtModule.register({
            secretOrPrivateKey: 'iron-nest',
            // signOption可以在JwtModule設定
            // 或是在createToken時候設定
            signOptions:{
//                expiresIn: 3600,
                issuer:'http://iron-nest.org'
            }
        }),
        UserModule,
    ],
    controllers:[AuthController],
    providers: [
        ...
        JwtStrategy,
    ],
})
export class AuthModule {}

設定defaultStrategy

昨天用@AuthGuard()要傳入Strategy名稱,透過PassportModule.register可以設定defaultStrategy,
在該module下就不用每次都要指定Strategy,除非是例外

    @Module({
    imports: [
        
        // 指定strategy,不用在AuthGuard裡特別指定
        // PassportModule.register({defaultStrategy: 'bearer'})
        PassportModule.register({defaultStrategy: 'jwt'}),
        SharedModule, // import shared module
        TypeOrmModule.forFeature([...userEntities]), // forFeature告訴nest.js在typeorm要存取相關的entity
    ],
   ...
})
export class UserModule {}

修改Users Controller把AuthGuard引數拿掉

@UseGuards(AuthGuard())
@Controller('users')
export class UsersController {
...
}

測試

錯誤token

取得Token

指定Authorization token


Github Source Code


上一篇
Day24 Http Bearer Token保護API End Point-使用Passport
下一篇
Day26 用Nestjs Decorator建立Swagger API Doc
系列文
讀官網文件邊走邊學nest.js31

尚未有邦友留言

立即登入留言