nestjs中passport鉴权部署流程

2023年 8月 15日 44.1k 0

按官方说明,鉴权主要分两步:

① LocalStrategy本地策略对用户名和密码进行比对

② 第①项登录成功后,JwtStrategy根据payload签名返回token;或者从Headers解析验证token是否有效

部署流程

① 需要创建auth module, auth service, strategy(local/jwt), guard(local/ jwt)

② 总体原理就是:

  • 守卫Guard作为装饰器对需要鉴权的接口进行策略注入 (??可能会自动调用passport??)
  • 本地策略localstrategy主要校验用户名密码是否和数据库一致,失败抛出未认证错误;成功则返回用户信息,执行下一步我们定义的login方法,返回access_token
  • jwt策略进行token处理,自动从headers读取token进行认证判断
  • 两种策略都会自动执行validate函数里我们定义好的逻辑
  • // auth.module.ts
    
    import { Module } from '@nestjs/common';
    import { AuthService } from './auth.service';
    import { PassportModule } from '@nestjs/passport';
    import { JwtModule } from '@nestjs/jwt';
    import { LocalStrategy } from './strategy/local';
    import { JwtStrategy } from './strategy/jwt';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { Users } from 'src/userinfo/entities/users.entity';
    
    @Module({
      imports: [ 
        // UserinfoModule, 
        TypeOrmModule.forFeature([Users]),
        PassportModule,
        JwtModule.register({
          secret: 'TEMPsecret',
          signOptions: { expiresIn: '120s' }
        })
      ], //
      providers: [AuthService , LocalStrategy, JwtStrategy],
      exports: [ AuthService ]
    })
    export class AuthModule {}
    
    
    // auth.service.ts
    
    import { Injectable } from '@nestjs/common';
    import { JwtService } from '@nestjs/jwt';
    import { InjectRepository } from '@nestjs/typeorm';
    import { Users } from 'src/userinfo/entities/users.entity';
    import { Repository } from 'typeorm';
    
    @Injectable()
    export class AuthService {
        constructor(
            @InjectRepository(Users) private readonly usersRepository:  //  调用数据库必须进行注入
                Repository,
            private jwtService: JwtService
            ){}
        async validateUser(username: string, password: string ): Promise {
            const user = await this.usersRepository.findOne({ where: {username} })
            if (user && user.password === password) {
              const { password, ...result } = user;
              return result;
            }
            return null;
          }
          async login(userinfo) {
            const payload = { username: userinfo.username, sub: 'any msg' };
            return {
              access_token: this.jwtService.sign(payload),
            };
          }
    }
    
    
    // jwt.strategy.ts
    
    import { Strategy } from 'passport-jwt';  //注意此处引入来源和local不同
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable } from '@nestjs/common';
    import { ExtractJwt } from 'passport-jwt';
    
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor() {
        super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          ignoreExpiration: false,
          secretOrKey: 'TEMPsecret',
        });
      }
      async validate(payload: any) {
        return { userId: payload.sub, username: payload.username };
      }
    }
    
    //local.strategy.ts
    
    import { Strategy } from 'passport-local';
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { AuthService } from '../auth.service';
    
    @Injectable()
    export class LocalStrategy extends PassportStrategy(Strategy) {
      constructor(private authService: AuthService) {
        super();
      }
        //  此函数会在useguard装饰后直接执行进行校验
        // 如果传递的是json数据会有异常,所以暂时还是改用表单数据
      async validate(username: string, password: string): Promise {
        const user = await this.authService.validateUser(username, password);
        if (!user) {
          throw new UnauthorizedException();
        }
        // 这里返回用户信息供后面进行payload传token
        return user;
      }
    }
    
    // auth.guard.ts
    
    import { Injectable } from '@nestjs/common';
    import { AuthGuard } from '@nestjs/passport';
    
    //  定义两个passport的守卫类型
    @Injectable()
    export class LocalAuthGuard extends AuthGuard('local') {}
    
    @Injectable()
    export class JwtAuthGuard extends AuthGuard('jwt') {}
    
    

    需要用到的controller文件里引用UseGuards

     @UseGuards(LocalAuthGuard)
      @Post('login')
      signIn(@Body() userinfo: any){
        // console.log("🚀 ~ file: userinfo.controller.ts:30 ~ UserinfoController ~ signIn ~ userinfo:", userinfo)
        // 如果上面守卫校验通过了,则会执行下面的登录返回token时间
        return this.authService.login(userinfo)
      }
      
     //  其他需要验证token的请求直接添加装饰器即可
     //   @UseGuards(JwtAuthGuard)
    

    记得到本模块module里引入AuthModule, 不然无法调用authService

    以上代码有个缺点,所有接口都定义在引入module里,这样会导致调用数据库时service循环引用(曲线解决: authModule里直接引用数据库查询TypeOrmModule),所以最好是将注册认证接口定义到authModule的controller控制器里,然后调用userService即可

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论