You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AWS CDK v2的ApiGatewayV2 Websocket中添加自定义授权器?

如何在AWS CDK v2的ApiGatewayV2 Websocket中添加自定义授权器?

我来帮你一步步拆解这个问题,结合你现有的代码梳理清楚每个关键点:


一、能不能复用现有的自定义授权器函数?

完全可以!你之前写的Auth0验证Lambda函数逻辑可以直接复用,只需要调整CDK中授权器的配置——因为WebSocket API的授权器和REST API的CfnAuthorizer结构略有不同,但核心的认证逻辑(比如验证JWT)不需要改动。

二、WebSocket授权的特殊之处?

WebSocket的授权逻辑只在$connect路由触发——这是客户端建立连接时的唯一校验机会,一旦连接成功建立,后续的自定义路由(比如你写的completions)不会再自动触发授权(如果需要二次校验,得自己在业务Lambda里处理)。

另外,WebSocket的身份信息来源和REST API不同,它支持从握手请求的header或者query参数里取认证token,因为WebSocket的连接本质是一次HTTP握手请求。

三、前端怎么授权WebSocket连接?

和HTTP请求类似,前端建立WebSocket连接时可以通过两种方式传认证信息:

  • 查询参数:比如 wss://your-api.execute-api.region.amazonaws.com/stage?Authorization=Bearer<你的token>
  • 请求头:部分WebSocket客户端(比如ws库)支持自定义握手header,写法类似 headers: { Authorization: 'Bearer <你的token>' }(注意:浏览器原生WebSocket API不支持自定义header,这种情况只能用查询参数)

四、具体的CDK v2代码修改步骤

结合你现有的代码,我们一步步调整:

1. 为WebSocket创建专属的CfnAuthorizer

在你的addWebsocket方法中,添加WebSocket授权器的配置(复用之前的Lambda函数和角色):

// 复用你之前定义的authorizerHandler和role
const websocketAuthorizer = new CfnAuthorizer(this, 'WebsocketThingAuthoriser', {
  apiId: websocketApi.api.ref, // 这里必须填WebSocket API的ref,不是REST API的
  name: 'websocket-thing-authoriser',
  type: 'REQUEST', // WebSocket自定义授权器必须用REQUEST类型,不能用REST API的TOKEN类型
  authorizerUri: `arn:aws:apigateway:${environment.REGION}:lambda:path/2015-03-31/functions/${authorizerHandler.functionArn}/invocations`,
  authorizerCredentials: role.roleArn, // 复用之前创建的role即可
  identitySource: [
    '$request.header.Authorization', // 支持从header取token
    '$request.querystring.Authorization' // 同时支持从查询参数取token,可按需选择
  ]
});

2. 修改$connect路由的授权配置

调整你的WebsocketApi类中的addLambdaIntegration方法,让它支持传入授权器ID,然后在创建$connect路由时关联授权器:

addLambdaIntegration(handler: IFunction, routeKey: string, operationName: string, apiKeyRequired?: boolean, authorizationType?: string, authorizerId?: string) {
  const integration = new CfnIntegration(this, `${operationName}Integration`, {
    apiId: this.api.ref,
    integrationType: "AWS_PROXY",
    integrationUri: `arn:aws:apigateway:${Aws.REGION}:lambda:path/2015-03-31/functions/${handler.functionArn}/invocations`
  });

  handler.grantInvoke(new ServicePrincipal('apigateway.amazonaws.com', {
    conditions: {
      "ArnLike": {
        "aws:SourceArn": `arn:aws:execute-api:${Aws.REGION}:${Aws.ACCOUNT_ID}:${this.api.ref}/*/*`
      }
    }
  }));

  const routeProps: CfnRouteProps = {
    apiId: this.api.ref,
    routeKey,
    apiKeyRequired,
    authorizationType: authorizationType || "NONE",
    operationName,
    target: `integrations/${integration.ref}`
  };

  // 如果传入授权器ID,添加到路由配置
  if (authorizerId) {
    routeProps.authorizerId = authorizerId;
  }

  this.deployment.addDependency(new CfnRoute(this, `${operationName}Route`, routeProps));
}

然后在创建$connect路由时,指定授权类型和授权器:

// 在WebsocketApi构造函数的$connect路由处修改:
this.addLambdaIntegration(
  props.connectHandler, 
  "$connect", 
  "ConnectionRoute",
  false,
  "CUSTOM", // 指定授权类型为自定义
  websocketAuthorizer.ref // 关联我们创建的WebSocket授权器
);

3. 调整授权器Lambda函数的返回格式

WebSocket授权器的返回格式和REST API的不一样,需要改成{ isAuthorized: boolean, context?: object }的结构,所以你的auth0-authoriser.ts需要调整:

export const handler = async (event: any) => {
  // 从header或query参数中获取token
  const token = event.headers?.Authorization || event.queryStringParameters?.Authorization;
  if (!token) {
    return {
      isAuthorized: false,
      context: {}
    };
  }

  // 保留你原来的Auth0验证逻辑...
  const isValid = await validateToken(token);

  return {
    isAuthorized: isValid,
    context: {
      // 可选:返回上下文信息,后续业务Lambda可通过event.requestContext.authorizer获取
      userId: 'xxx'
    }
  };
};

五、验证和测试

  1. 部署修改后的CDK栈
  2. 前端连接WebSocket时,通过header或查询参数带上Authorization token
  3. 如果授权失败,API Gateway会直接拒绝连接并返回403
  4. 授权成功后,连接建立,后续的消息会携带requestContext.authorizer里的上下文信息

备注:内容来源于stack exchange,提问作者OrderAndChaos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 14:14:38