如何为所有Cognito身份(含桌面、移动端)附加IoT策略?
问题根因
你遇到的报错本质是触发场景和官方文档描述的场景不匹配:
官方文档提到的
context.cognito_identity_id字段存在的前提是:Lambda函数由用户持Cognito身份池颁发的凭证直接调用。而你现在用的是Cognito用户池的Post Confirmation触发器,这个场景下Lambda是由Cognito服务内部调用的,调用主体不是用户身份,因此context对象完全不会携带identity相关字段,自然会报属性不存在的错误。
另外你代码里还有一个隐藏问题:IoT的attachPolicy接口的policyName参数要求传入IoT策略的名称字符串,不能传策略ARN,否则也会调用失败。
最优实现方案(适配所有端用户)
不需要依赖Lambda context属性,也不用区分桌面/移动端,推荐直接使用Cognito身份池的同步触发器实现,流程如下:
- 打开你的Cognito身份池配置,找到「同步触发器」配置项,绑定你的Lambda函数
- 当任意端的用户首次在身份池中创建身份时,Lambda会被触发,event对象中会直接携带
identityId字段,无需自行查询 - 给Lambda执行角色添加
iot:AttachPolicy权限
修改后的Lambda代码示例:
const AWS = require('aws-sdk'); const iot = new AWS.Iot(); // 替换为你自己创建的IoT策略名称,注意不是ARN const IOT_POLICY_NAME = '你的IoT策略名称'; exports.handler = async function(event, context) { // 直接从触发器event中获取身份ID,所有端用户触发时都有这个字段 const target = event.identityId; await iot.attachPolicy({ target, policyName: IOT_POLICY_NAME }).promise(); // 身份池触发器要求返回event对象继续后续流程,不要返回自定义响应 return event; };
如果你坚持要使用用户池Post Confirmation触发器实现
需要先完成前置配置:确保你的Cognito用户池已经作为身份提供者关联到目标身份池。
实现逻辑是从Post Confirmation触发器的event中提取用户属性,调用Cognito Identity接口查询对应的身份ID,再附加策略:
- 给Lambda执行角色添加两个权限:
cognito-identity:GetId、iot:AttachPolicy - 修改代码如下:
const AWS = require('aws-sdk'); const iot = new AWS.Iot(); const cognitoIdentity = new AWS.CognitoIdentity(); // 替换为你自己的配置 const IOT_POLICY_NAME = '你的IoT策略名称'; const IDENTITY_POOL_ID = '你的区域:xxxx-xxxx-xxxx-xxxx'; const USER_POOL_ID = '你的区域_xxxxxxxxx'; const USER_POOL_PROVIDER = `cognito-idp.${USER_POOL_ID.split('_')[0]}.amazonaws.com/${USER_POOL_ID}`; exports.handler = async function(event, context) { // 从触发器event中获取用户唯一标识sub和最新的ID令牌 const userSub = event.request.userAttributes.sub; const userIdToken = event.request.userAttributes.idToken; // 部分触发器版本需要自行从event中提取ID令牌 // 查询对应用户的身份池ID const idResp = await cognitoIdentity.getId({ IdentityPoolId: IDENTITY_POOL_ID, Logins: { [USER_POOL_PROVIDER]: userIdToken } }).promise(); const target = idResp.IdentityId; await iot.attachPolicy({ target, policyName: IOT_POLICY_NAME }).promise(); // Post Confirmation触发器要求返回event对象 return event; };
如果你的Post Confirmation触发器event中无法获取到用户ID令牌,建议优先使用身份池触发器方案。
内容的提问来源于stack exchange,提问作者David U
相关产品推荐
相关产品推荐

