NestJS - 使用令牌授权与 HttpOnly Cookie

问题描述 投票:0回答:1

我已经根据文档在 NestJS 中创建了一个登录系统,但我对授权方法有疑问。根据文档,用户登录后会收到一个token,每次需要发送到API进行授权。

我的问题是:这真的是正确的方法吗?使用 HttpOnly cookie 来存储令牌不是更好吗?在 NestJS 的上下文中应该如何实现? 验证服务:

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersService } from '../users/users.service';
import { JwtService } from '@nestjs/jwt';

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

  async signIn(
    username: string,
    pass: string,
  ): Promise<{ access_token: string }> {
    const user = await this.usersService.findOne(username);
    if (user?.password !== pass) {
      throw new UnauthorizedException();
    }
    const payload = { sub: user.userId, username: user.username };
    return {
      access_token: await this.jwtService.signAsync(payload),
    };
  }
}

身份验证控制器

import {
    Body,
    Controller,
    Get,
    HttpCode,
    HttpStatus,
    Post,
    Request,
    UseGuards
} from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthGuard } from './auth.guard';

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

  @HttpCode(HttpStatus.OK)
  @Post('login')
  signIn(@Body() signInDto: Record<string, any>) {
    return this.authService.signIn(signInDto.username, signInDto.password);
  }

  @UseGuards(AuthGuard)
  @Get('profile')
  getProfile(@Request() req) {
    return req.user;
  }
}

授权守卫

import {
    CanActivate,
    ExecutionContext,
    Injectable,
    UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { jwtConstants } from './constants';
import { Request } from 'express';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const token = this.extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      const payload = await this.jwtService.verifyAsync(
        token,
        {
          secret: jwtConstants.secret
        }
      );
      request['user'] = payload;
    } catch {
      throw new UnauthorizedException();
    }
    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}

您认为哪种方法更好?我应该遵循文档中的内容并将令牌存储在 React 中,在需要时发送它,还是使用 HttpOnly cookies?

javascript nestjs backend
1个回答
0
投票

您的项目首选的身份验证方法完全取决于您的项目的要求。基于令牌和 cookie 的方法都有各自的优点和缺点。 Nest.js 作为一个框架使您能够实现这两种方法。

基于 Cookie 的身份验证

  • 这是一种有状态的方法。

  • 服务器对客户端进行身份验证,向客户端发送签名的 cookie 并打开会话。客户端将 cookie 与每个后续身份验证请求一起发送。

  • 服务器通过这种方式维护会话信息。客户端注销后会话将被刷新。

  • 基于 Cookie 的身份验证不需要在客户端进行设置。浏览器默认处理该问题。您还可以将 cookie 设置为 HttpOnly,这使得客户端 javascript 无法访问它们,从而确保安全。

  • Cookie 被严格锁定到特定域。您不能在域之间使用 cookie,因为会话位于服务器上。

基于令牌的身份验证

  • 这是一种无状态的方法。

  • 服务器对客户端进行身份验证,并将签名令牌发送回客户端,其中包含散列密钥。客户端将令牌附加在每个请求的标头中,由服务器解析和验证以确保完整性。

  • 这需要在客户端进行设置来管理令牌。客户端负责存储和更新有效令牌。

结论

  • HTTP 是无状态协议。基于令牌的方法确保客户端的完整性,并确保无状态方法。基于 Cookie 的身份验证会导致客户端和服务器之间有状态会话。

  • 令牌可以跨域共享,确保与特定于域的 cookie 不同,适合微服务架构。

基于令牌的方法会带来更灵活的方法,尽管它需要您编写一些手动代码。

© www.soinside.com 2019 - 2024. All rights reserved.