如何在Amplify/Cognito中配合Auth.federatedSignIn()使用@auth owner指令
问题根源
你当前遇到的@auth(rules: [{ allow: owner }])不生效的核心原因是:你调用的Auth.federatedSignIn()(传入身份提供商名称、令牌、用户信息的重载方法)走的是**Cognito身份池(联邦身份)**的认证流程,只会颁发IAM访问凭证,不会在Cognito用户池中生成对应用户条目。而@auth(rules: [{ allow: owner }])默认依赖Cognito用户池颁发的ID令牌中的sub/cognito:username声明,因此无法正常识别用户身份做权限隔离。
可行解决方案
你不需要使用托管UI跳转,只要调整认证流程,将Facebook原生登录获取的令牌,兑换为Cognito用户池的JWT令牌即可,具体步骤如下:
- 第一步:在AWS Cognito用户池控制台中,将Facebook配置为第三方身份提供商(IdP),填入你的Facebook应用ID、密钥,配置属性映射(比如将Facebook返回的
id映射为用户池的username,email映射为用户池的email)。 - 第二步:保留你当前用capacitor-facebook-login获取Facebook访问令牌的逻辑,替换后续的认证逻辑:不再调用原有的身份池版
Auth.federatedSignIn(),而是用Facebook令牌兑换Cognito用户池的JWT令牌,再手动注入Amplify Auth会话。
参考代码如下:
import { Auth } from 'aws-amplify'; import { CognitoIdentityProviderClient, InitiateAuthCommand } from "@aws-sdk/client-cognito-identity-provider"; // 初始化Cognito Identity Provider客户端,替换为你自己的用户池配置 const cognitoClient = new CognitoIdentityProviderClient({ region: "你的Cognito用户池所在区域", }); const FBLogIn = async () => { const result = await FacebookLogin.login({ permissions: FACEBOOK_PERMISSIONS }); const { email } = await FacebookLogin.getProfile({ fields: ['email'] }); const fbAccessToken = result.accessToken.token; const fbUserId = result.accessToken.userId; try { // 调用Cognito用户池接口,用Facebook令牌兑换用户池JWT const authResponse = await cognitoClient.send(new InitiateAuthCommand({ AuthFlow: "CUSTOM_AUTH", ClientId: "你的Cognito用户池App客户端ID", AuthParameters: { USERNAME: fbUserId, PASSWORD: fbAccessToken, } })); const { IdToken, AccessToken, RefreshToken } = authResponse.AuthenticationResult; // 手动设置Amplify登录会话 const userSession = { getIdToken: () => ({ getJwtToken: () => IdToken }), getAccessToken: () => ({ getJwtToken: () => AccessToken }), getRefreshToken: () => ({ getToken: () => RefreshToken }), isValid: () => true }; await Auth.setSignInUserSession(userSession); // 此时Cognito已自动在用户池中创建对应用户,后续GraphQL请求的@auth(allow: owner)规则会正常生效 } catch (error) { console.log(error) } }
你需要额外在Cognito用户池配置自定义认证Lambda触发器,用来验证Facebook令牌的有效性:触发器接收Facebook用户ID和令牌,调用Facebook令牌验证接口确认有效性后返回认证成功即可。
如果不想编写Lambda,也可以在配置完Cognito用户池的Facebook IdP后,直接通过Cognito OAuth2 token端点的token-exchange授权类型直接兑换用户池JWT,不需要额外开发触发器。
配置完成后,你可以直接在GraphQL Schema中使用@auth(rules: [{ allow: owner }])规则,Cognito会自动识别当前登录用户的sub作为所有者标识,实现用户仅能查看自有数据的权限隔离。
内容的提问来源于stack exchange,提问作者webdog

