怎么用Nest.js实现passport策略jwt鉴权:构建一个既安全又高效的身份验证系统

在现代Web应用程序开发中,身份验证是确保用户安全访问受保护资源的关键环节。特别是在Node.js生态系统中,Passport作为一个功能强大且广泛使用的身份验证中间件库,为开发者提供了灵活且可扩展的身份验证解决方案。本文将深入探讨如何在NestJS框架中集成Passport,通过实现账户密码策略和JWT策略,来优化身份验证流程,提升应用程序的安全性和用户体验。

一、Passport的基础知识和基本功能

首先,让我们从Passport的基础开始:

Passport本身可以看作一框架

Passport是最流行的node.js身份验证库

使用策略模式(设计模式),决定当前是获取 token还是解析 token

使用 @nestjs/passport 模块,可以很容易地将这个库与 Nest 应用程序集成。

Passport 提供了一种名为 Passport-local 的策略,它实现了一种用户名/密码身份验证机制。

Passport-jwt 就是实现JWT解析身份验证机制。

二、怎么在Passport中生成jwt策略

Passport提供了多种身份验证策略,其中Passport-local实现了用户名/密码身份验证机制,而Passport-jwt则实现了JWT解析身份验证机制。为了生成JWT,我们需要使用@nestjs/jwt模块提供的JwtService,该服务提供了sign()方法用于生成JWT。在NestJS中,我们通常会创建一个AuthService服务来封装与身份验证相关的逻辑,包括登录验证、用户验证等。

需要用到的模块:

  • @nestjs/jwt,提供了JwtService,可以直接用sign()方法返回名。
import { checkPassword } from '@libs/common/utils/password';
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { User } from '@prisma/client';
import { PayloadDto } from 'apps/admin/src/auth/dto/payload.dto';
import { UsersService } from 'apps/admin/src/users/users.service';

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService,
  ) {}

  login(user: User) {
    const payload: PayloadDto = { id: user.id };
    return { token: this.jwtService.sign(payload) }; // 返回json web token
  }

  async validateUser(email: string, password: string): Promise<User> {
    const user = await this.usersService.getUserByEmail(email);

    if (!checkPassword(user.password, password)) {
      return null;
    }

    return {
      ...user,
      password: undefined, // 密碼不做返回
    };
  }
}

直接注入依赖就完事了

三、怎么配置Passport的本地策略

接下来,我们将通过扩展PassportStrategy类来配置Passport的本地策略(即账户密码策略)。

使用 @nestjs/passport,您可以通过扩展 PassportStrategy 类来配置 passport 策略。

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { User } from '@prisma/client';
import { AuthService } from 'apps/admin/src/auth/auth.service';
import { Strategy } from 'passport-local';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super({ usernameField: 'email', passwordField: 'password' });
  }

  validate(email: string, password: string): Promise<User> {
    return this.authService.validateUser(email, password);
  }
}

第一个参数对应用户名字段(usernameFiled)的值,第二个参数对应密码字段(passwordFiled)的值。

通过调用子类中的 super() 方法传递策略选项,可以选择传递一个选项对象。

对于每个策略,Passport将使用适当的特定于策略的一组参数调用验证函数(使用@nestjs/Passport中的valitor()方法实现。

passport-local是Passport提供的一种本地身份验证策略,它使用用户名和密码来验证用户。

代码中,重新配置了用户名、密码字段名字。

这意味着在验证用户凭据时,本地策略将期望从传递给验证方法的参数中读取'email''密码'字段的值。

这里的字段,对应著DTO字段。

import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';

export class LoginDto {
  @ApiProperty({
    description: '用戶郵箱',
    default: 'Taoister39@outlook.com',
    required: true,
  })
  @IsString()
  readonly email: string;

  @ApiProperty({
    description: '用戶密碼',
    default: '123456',
    required: true,
  })
  @IsString()
  readonly password: string;
}

四、怎么实现JWT策略模式

除了本地策略外,我们还需要实现JWT策略来支持基于token的身份验证。

passport-jwt包是实现JWT策略的Passport包,@type/passport-jwt提供TypeScript类型定义。

import { PassportStrategy } from '@nestjs/passport';
import { PayloadDto } from 'apps/admin/src/auth/dto/payload.dto';
import { ExtractJwt, Strategy } from 'passport-jwt';

export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    // console.log(process.env.JWT_SECRET, ' jwt secret ');
    super({
      secretOrKey: process.env.JWT_SECRET,
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // 從請求頭中提取token
      ignoreExpiration: false, // 過期自動返回401錯誤
    });
  }
  // jwt裏只攜帶了id
  async validate(payload: PayloadDto) {
    return payload;
  }
}

对于JWT策略,Passport首先验证JWT的签名并解码JSON.然后调用我们的valdit()方法,该方法将解码后的JSON作为其单个参数传递。

五、JwtModule和PassportModule的集成与应用

最后,我们需要将上述策略、JwtModule和PassportModule集成到NestJS应用程序中。这通常涉及到在AuthModule中导入这些模块和提供者,并配置JwtModule的相关选项(如密钥和签名选项)。通过AuthGuard守卫,我们可以决定在特定的路由或控制器中使用哪种身份验证策略。

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { LocalStrategy } from 'apps/admin/src/auth/strategy/local.strategy';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from 'apps/admin/src/auth/strategy/jwt.strategy';
import { UsersModule } from 'apps/admin/src/users/users.module';

@Module({
  controllers: [AuthController],
  providers: [AuthService, LocalStrategy, JwtStrategy],
  imports: [
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: {
        expiresIn: '1d', // token 有效爲 1天
      },
    }),
    UsersModule,
    PassportModule,
  ],
})
export class AuthModule {}

首先提供刚刚的策略,然后导入JwtModulePassportModule,对应的JwtService就可以注入依赖,以及通过封装的策略,在应用中加载。通过AuthGuard守卫决定使用哪个策略。

结语

通过在NestJS中集成Passport并实现账户密码策略和JWT策略,我们可以构建一个既安全又高效的身份验证系统。这不仅提升了应用程序的安全性,还优化了用户体验。随着技术的不断发展和用户需求的不断变化,我们将继续探索和优化身份验证的最佳实践,以确保我们的应用程序始终能够为用户提供安全、便捷的访问体验。

延展阅读:

大促期间客服容易漏回消息?电商商家怎么用智能工具高效提升客服响应速度?

智能客服回复不准确影响客户满意度?电商商家怎么通过数据分析快速提高其应答水平

顾客没耐心等人工,电商商家怎么通过智能客服自助服务提升询单转化率

咨询方案 获取更多方案详情                        
(0)
研发专家-天华研发专家-天华
上一篇 2024年10月30日 下午6:48
下一篇 2024年10月31日 下午6:43

相关推荐