返回介绍

nest 基于 possport + jwt 做登陆验证

发布于 2024-01-18 22:07:39 字数 5314 浏览 0 评论 0 收藏 0

方式与逻辑

  • 基于 possport 的本地策略和 jwt 策略
  • 本地策略主要是验证账号和密码是否存在,如果存在就登陆,返回token
  • jwt 策略则是验证用户登陆时附带的 token是否匹配和有效,如果不匹配和无效则返回401 状态码
yarn add @nestjs/jwt @nestjs/passport passport-jwt passport-local passport
yarn add -D @types/passport @types/passport-jwt @types/passport-local

jwt 策略 jwt.strategy.ts

// src/modules/auth/jwt.strategy.ts
import { Strategy, ExtractJwt, StrategyOptions } from 'passport-jwt';
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { jwtConstants } from './constants';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromHeader('token'),
      ignoreExpiration: false,
      secretOrKey: jwtConstants.secret, // 使用密钥解析
    } as StrategyOptions);
  }

  //token 验证, payload 是 super 中已经解析好的 token 信息
  async validate(payload: any) {
    return { userId: payload.userId, username: payload.username };
  }
}

本地策略 local.strategy.ts

// src/modules/auth/local.strategy.ts
import { Strategy, IStrategyOptions } from 'passport-local';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { AuthService } from './auth.service';

//本地策略
//PassportStrategy 接受两个参数:
//第一个:Strategy,你要用的策略,这里是 passport-local,本地策略
//第二个:别名,可选,默认是 passport-local 的 local,用于接口时传递的字符串
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super({
      usernameField: 'username',
      passwordField: 'password',
    } as IStrategyOptions);
  }

  // validate 是 LocalStrategy 的内置方法
  async validate(username: string, password: string): Promise<any> {
    //查询数据库,验证账号密码,并最终返回用户
    return await this.authService.validateUser({ username, password });
  }
}

constants.ts

// src/modules/auth/constants.ts
export const jwtConstants = {
  secret: 'secretKey',
};

使用守卫 auth.controller.ts

// src/modules/auth/auth.controller.ts
import { Controller, Get, Post, Request, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  // 登录测试 无需 token
  @UseGuards(AuthGuard('local')) //本地策略,传递 local,执行 local 里面的 validate 方法
  @Post('login')
  async login(@Request() req) { //通过 req 可以获取到 validate 方法返回的 user,传递给 login,登陆
    return this.authService.login(req.user);
  }
  // 在需要的地方使用守卫,需要带 token 才可访问
  @UseGuards(AuthGuard('jwt'))//jwt 策略,身份鉴权
  @Get('userInfo')
  getUserInfo(@Request() req) {//通过 req 获取到被验证后的 user,也可以使用装饰器
    return req.user;
  }
}

在 module 引入 jwt 配置和数据库查询的实体 auth.module.ts

// src/modules/auth/auth.module.ts
import { LocalStrategy } from './local.strategy';
import { jwtConstants } from './constants';
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { UsersEntity } from '../user/entities/user.entity';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forFeature([UsersEntity]),
    PassportModule,
    JwtModule.register({
      secret: jwtConstants.secret,
      signOptions: { expiresIn: '10d' },
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService, LocalStrategy, JwtStrategy],
  exports: [AuthService],
})
export class AuthModule {}

auth.service.ts

// src/modules/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { compareSync } from 'bcryptjs';

@Injectable()
export class AuthService {
  constructor(
  @InjectRepository(UsersEntity),
       private readonly usersRepository: Repository<UsersEntity>,
  private jwtService: JwtService
    ) {}
  
  validateUser(username: string, password: string) {
    const user = await this.usersRepository.findOne({
      where: { username },
      select: ['username', 'password'],
    });
    if (!user) ToolsService.fail('用户名或密码不正确');
    //使用 bcryptjs 验证密码
    if (!compareSync(password, user.password)) {
      ToolsService.fail('用户名或密码不正确');
    }
    return user;
  }
  login(user: any) {
    const payload = { username: user.username };  // 把信息存在 token
    return {
      token: this.jwtService.sign(payload),
    };
  }
}

最后在 app.module.ts 中导入即可测试

// app.modules.ts
import { AuthModule } from './modules/auth/auth.module';

@Module({
  imports: [
    ...
    AuthModule, // 导入模块
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule implements NestModule {}

使用 postman 测试

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文