Angular项目:Cognito用户关联个人S3桶权限及凭证缺失问题
问题描述
开发的系统包含两部分:桌面应用支持用户登录后上传文件到个人Amazon S3桶;网页端允许用户通过Cognito账号登录,查看/下载自己桶内的文件。目前桌面应用功能正常,但网页端无法关联Cognito用户与对应S3桶的权限,调用ListBuckets接口时返回Error: Credential is missing错误。
AWS Amplify认证代码(输入凭证可成功获取用户)
export class CognitoService { private authenticationSubject: BehaviorSubject<any>; constructor() { Amplify.configure({ Auth: environment.cognito, }); this.authenticationSubject = new BehaviorSubject<boolean>(false); } public signIn(user: IUser): Promise<any> { return Auth.signIn(user.username, user.password) .then(returnedUser => { if (returnedUser.challengeName === 'NEW_PASSWORD_REQUIRED') { Auth.completeNewPassword(returnedUser, user.password) .then(user => { return user }); } }) } public getUser(): Promise<any> { return Auth.currentUserInfo(); } }
获取数据代码(获取S3桶请求失败)
export class DataComponent implements OnInit{ user: IUser; constructor(private cognitoService: CognitoService, private s3Service: S3Service) { this.user = {} as IUser; } public ngOnInit(): void { this.cognitoService.getUser() .then((user: any) => { this.user = user.attributes; }); } public getBuckets(): void { this.s3Service.getBuckets() .then((response: any) => { console.log(response) }) } }
获取桶的S3服务代码(怀疑需修改此处)
export class S3Service { constructor() { Amplify.configure({ Auth: environment.cognito, }); } public async getBuckets() { const client = new S3Client({region: 'us-west-2'}); const input = {}; const command = new ListBucketsCommand(input); const response = await client.send(command); } }
环境配置
export const environment = { cognito: { userPoolId: 'xxx', userPoolWebClientId: 'xxx', }, }
解决方案
问题核心是S3客户端未获取到Cognito用户的临时凭证,同时代码存在几处需修正的细节:
1. 修正S3Service,注入Cognito凭证
先安装依赖:@aws-sdk/credential-provider-cognito-identity,然后修改S3Service代码:
import { Auth } from 'aws-amplify'; import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3'; import { fromCognitoIdentityPool } from '@aws-sdk/credential-provider-cognito-identity'; export class S3Service { // 无需重复配置Amplify,CognitoService已完成初始化 constructor() {} public async getBuckets() { // 校验用户登录状态 const authenticatedUser = await Auth.currentAuthenticatedUser(); if (!authenticatedUser) throw new Error('用户未登录'); // 获取Cognito身份凭证 await Auth.currentUserCredentials(); // 配置S3客户端,关联Cognito身份池临时凭证 const client = new S3Client({ region: 'us-west-2', credentials: fromCognitoIdentityPool({ clientConfig: { region: 'us-west-2' }, identityPoolId: environment.cognito.identityPoolId, // 需在环境变量中添加身份池ID logins: { [`cognito-idp.us-west-2.amazonaws.com/${environment.cognito.userPoolId}`]: authenticatedUser.signInUserSession.idToken.jwtToken } }) }); const command = new ListBucketsCommand({}); const response = await client.send(command); return response; } }
2. 更新环境配置,添加Cognito身份池ID
身份池是关联用户池与S3权限的核心,补充环境变量:
export const environment = { cognito: { userPoolId: 'xxx', userPoolWebClientId: 'xxx', identityPoolId: 'us-west-2:xxxx-xxxx-xxxx-xxxx-xxxx' // 替换为你的身份池ID }, }
3. 修复CognitoService的signIn方法
原代码中completeNewPassword的Promise未返回,导致密码重置后无法正确获取用户信息:
public signIn(user: IUser): Promise<any> { return Auth.signIn(user.username, user.password) .then(returnedUser => { if (returnedUser.challengeName === 'NEW_PASSWORD_REQUIRED') { // 返回Promise确保外层等待操作完成 return Auth.completeNewPassword(returnedUser, user.password); } return returnedUser; }); }
4. 配置Cognito身份池的S3权限
登录AWS控制台,进入Cognito身份池的认证角色,添加IAM策略(可根据需求缩小权限范围,比如仅允许访问用户专属桶):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListAllMyBuckets", "Resource": "arn:aws:s3:::*" }, { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::user-${cognito-identity.amazonaws.com:sub}", "arn:aws:s3:::user-${cognito-identity.amazonaws.com:sub}/*" ] } ] }
5. 确保调用getBuckets时用户已登录
在DataComponent中,确认用户登录后再执行桶查询:
public ngOnInit(): void { this.cognitoService.getUser() .then((user: any) => { this.user = user.attributes; // 用户登录状态确认后再获取桶信息 this.getBuckets(); }) .catch(err => { console.log('用户未登录', err); }); }
内容的提问来源于stack exchange,提问作者Cameron Greenwalt
相关产品推荐
相关产品推荐

