如何识别来自不同租户nestjs多租户jwt的jwt令牌

Posted

技术标签:

【中文标题】如何识别来自不同租户nestjs多租户jwt的jwt令牌【英文标题】:how to recognized jwt token from different tenant nestjs muti-tenant jwt 【发布时间】:2020-06-23 03:05:39 【问题描述】:

我通过多个数据库实现多租户并使用jwt令牌作为授权,我担心的是当租户2的用户1登录并获取jwt令牌时,当他使用to令牌访问另一个租户时,他是否识别为用户租户 2 的 1?如果是这样,我们该如何解决?

我的策略

jwt.strategy.ts


@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) 
  constructor(
    private readonly configService: ConfigService,

    private readonly moduleRef: ModuleRef,
  ) 
    super(
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      passReqToCallback: true,
      secretOrKey: configService.get('JWT_SECRET_KEY'),
    );
  

  async validate(request: Request, jwtPayload: JwtPayload) 
    const contextId = ContextIdFactory.getByRequest(request);

    const authService: AuthService = await this.moduleRef.resolve(
      AuthService,
      contextId,
    );

    let  iat, exp  = jwtPayload;
    const timeDiff = exp - iat;

    if (timeDiff <= 0) 
      throw new UnauthorizedException();
    
    return jwtPayload;
  

我的身份验证服务

auth.service.ts


@Injectable( scope: Scope.REQUEST )
export class AuthService 
  constructor(
    private readonly jwtService: JwtService,
    private readonly configService: ConfigService,
    private readonly userService: UsersService,
    private readonly auctionHouseService: AuctionHouseService,
  ) 

  async createToken(user: User) 
    let plainUser: any = Object.assign(, user);
    plainUser.auctionHouseId = (
      await this.auctionHouseService.getCurrentAuctionHouse()
    ).id;
    return 
      expiresIn: this.configService.get('JWT_EXPIRATION_TIME'),
      accessToken: this.jwtService.sign(plainUser),
    ;
  


我的登录控制器

auth.controller.ts


@Controller('api/auth')
@ApiUseTags('authentication')
export class AuthController 
  constructor(
    private readonly authService: AuthService,
    private readonly userService: UsersService,
  ) 

  @Post('login')
  @ApiResponse( status: 201, description: 'Successful Login' )
  @ApiResponse( status: 400, description: 'Bad Request' )
  @ApiResponse( status: 401, description: 'Unauthorized' )
  async login(@Body() payload: LoginPayload, @Req() req): Promise<any> 
    let user = await this.authService.validateUser(payload);

    return omitPassword(await this.authService.createToken(user));
  

【问题讨论】:

要根据签名给用户授权吗? 为租户的签名令牌设置audience,并在验证用户时检查 @GuerricP 是的,因为它是一个多租户程序,如果租户 A 的用户 id 1 使用他的令牌访问租户 B,他将识别为用户 id 1 对吗? @Oluwafemi Sule ,看起来是个不错的解决方案?``` const contextId = ContextIdFactory.getByRequest(request);常量租户:TenancyIns = await this.moduleRef.resolve(INJECTION_SCOPE, contextId, strict: false , ); if (parseInt(tenant.aud) != tenancy.tenant.id) throw new UnauthorizedException(); ``` 【参考方案1】:

通常,识别 JWT 有效的域的正确方法是 aud(或受众)字段。每RFC7519:

“aud”(受众)声明标识 JWT 的接收者 用于。打算处理 JWT 的每个主体都必须 用受众声明中的价值来识别自己。如果校长 处理索赔并不表明自己具有价值 当此声明存在时,“aud”声明,则 JWT 必须是 被拒绝。在一般情况下,“aud”值是一个 case- 敏感字符串,每个都包含一个 StringOrURI 值。在里面 当 JWT 有一个受众的特殊情况下,“aud”值可能是 包含 StringOrURI 值的单个区分大小写的字符串。这 受众价值观的解释通常是特定于应用程序的。 使用此声明是可选的。

在您的上下文中,您希望为每个租户选择独特的受众(假设是 tenant1tenant2),并且在生成 JWT 时,您会执行以下操作:

plainUser.aud = this.configService.get("JWT_TENANT")

在验证令牌时,您将引入一项检查,以确认 aud 声明与当前租户匹配。

let  iat, exp, aud  = jwtPayload;
if (aud !== this.configService.get("JWT_TENANT")) 
  throw new UnauthorizedException();


// The rest of your validation code

注意我假设您将为每个租户运行具有不同配置的应用程序的多个应用程序实例,但是如果租户是从其他地方派生的,那么您应该从相关数据源收集该信息。

以这种方式接近它将确保您可以识别用户所属的用户和租户,并防止来自tenant1 的令牌被用于访问tenant2

【讨论】:

以上是关于如何识别来自不同租户nestjs多租户jwt的jwt令牌的主要内容,如果未能解决你的问题,请参考以下文章

每个客户端的 NestJs 多租户数据库 - 错误

Azure AD 多租户,.Net Core Web API 与 JWT 令牌

在多租户应用程序中如何检查应用程序在 Azure 门户中注册的租户数据?

LightSpeed 和多租户数据库

来自不同租户的 Azure AD 同意

如何授权来自不同 AAD 租户的特定客户端守护程序?