FORMA

认证与授权

  • 认证(Authentication):确认「你是谁」(如 JWT、Session)。
  • 授权(Authorization):确认「你能做什么」(如 RBAC、策略检查)。

NestJS 常用 @nestjs/passport + Guards 实现。守卫详见 guards;架构见 基础

JWT 流程(无状态 API)

  1. POST /auth/login:用 LocalStrategy 校验用户名密码,AuthService 签发 JWT。
  2. 后续请求:Authorization: Bearer <token>JwtStrategy + AuthGuard('jwt') 校验并将用户挂到 request.user

安装

bash
pnpm add @nestjs/passport passport passport-local passport-jwt @nestjs/jwt
pnpm add -D @types/passport-local @types/passport-jwt

AuthService(示例)

ts
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";

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

  async validateUser(username: string, pass: string) {
    const user = await this.findUser(username);
    if (!user || user.password !== pass) {
      throw new UnauthorizedException();
    }
    const { password, ...result } = user;
    return result;
  }

  login(user: { id: number; username: string }) {
    return {
      access_token: this.jwtService.sign({ sub: user.id, username: user.username }),
    };
  }

  private findUser(username: string) {
    /* 从数据库查询 */
    return null;
  }
}

LocalStrategy / JwtStrategy

ts
// local.strategy.ts
import { Strategy } from "passport-local";
import { PassportStrategy } from "@nestjs/passport";
import { Injectable } from "@nestjs/common";
import { AuthService } from "./auth.service";

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }
  async validate(username: string, password: string) {
    return this.authService.validateUser(username, password);
  }
}
ts
// jwt.strategy.ts
import { ExtractJwt, Strategy } from "passport-jwt";
import { PassportStrategy } from "@nestjs/passport";
import { Injectable } from "@nestjs/common";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: process.env.JWT_SECRET,
    });
  }
  validate(payload: { sub: number; username: string }) {
    return { userId: payload.sub, username: payload.username };
  }
}

控制器

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

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

  @UseGuards(AuthGuard("local"))
  @Post("login")
  login(@Request() req: { user: { id: number; username: string } }) {
    return this.authService.login(req.user);
  }

  @UseGuards(AuthGuard("jwt"))
  @Get("profile")
  getProfile(@Request() req: { user: unknown }) {
    return req.user;
  }
}

AuthModule 中注册 JwtModule.register({ secret, signOptions: { expiresIn: '1d' } }) 与上述 Provider。完整示例见官方 Authentication

RBAC(角色授权)

ts
// roles.decorator.ts
import { SetMetadata } from "@nestjs/common";
export const ROLES_KEY = "roles";
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
ts
// roles.guard.ts
import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { ROLES_KEY } from "./roles.decorator";

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const required = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    if (!required?.length) return true;
    const { user } = context.switchToHttp().getRequest();
    return required.some((role) => user?.roles?.includes(role));
  }
}
ts
@Roles("admin")
@UseGuards(AuthGuard("jwt"), RolesGuard)
@Get("admin")
adminOnly() {
  return { ok: true };
}

Session 与 OAuth

  • Session:在 Express 上使用 express-session 中间件(见 middleware);有状态,适合传统 SSR。
  • OAuth2:通过 Passport 策略(如 passport-google-oauth20),见官方 Passport recipes

细粒度规则可考虑 CASL,按资源与动作建模能力。

参考文献

以下链接在编写时均可正常访问:

资料说明
AuthenticationJWT 官方教程
Authorization授权
Passport策略集成
Guards守卫

Series

new

1 / 19