如何解决试图从 Lambda 获取图像,但访问被拒绝使用 Amplify 客户端库运行良好
我使用无服务器框架创建了 S3 Bucket,如下所示:
AssetsBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
Properties:
CorsConfiguration:
CorsRules:
- AllowedMethods:
- GET
- HEAD
- PUT
AllowedOrigins:
- '*'
AllowedHeaders:
- '*'
ExposedHeaders:
- 'x-amz-server-side-encryption'
- 'x-amz-request-id'
- 'x-amz-id-2'
- 'ETag'
MaxAge: 3000
然后,我创建了一个身份池并定义了我需要的角色:
IdentityPool:
Type: AWS::Cognito::IdentityPool
Properties:
AllowUnauthenticatedIdentities: true
CognitoIdentityProviders:
- ClientId: !Ref WebUserPoolClient
ProviderName: !GetAtt CognitoUserPool.ProviderName
CognitoAuthorizedRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref IdentityPool
ForAnyValue:StringLike:
"cognito-identity.amazonaws.com:amr": authenticated
CognitoUnAuthorizedRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref IdentityPool
ForAnyValue:StringLike:
"cognito-identity.amazonaws.com:amr": unauthenticated
IdentityPoolRoleMapping:
Type: AWS::Cognito::IdentityPoolRoleAttachment
Properties:
IdentityPoolId: !Ref IdentityPool
Roles:
authenticated: !GetAtt CognitoAuthorizedRole.Arn
unauthenticated: !GetAtt CognitoUnAuthorizedRole.Arn
这些角色有以下规则:
认知授权角色:
{
"Version": "2012-10-17","Statement": [
{
"Condition": {
"StringLike": {
"s3:prefix": [
"public/","public/*","protected/","protected/*","private/${cognito-identity.amazonaws.com:sub}/","private/${cognito-identity.amazonaws.com:sub}/*"
]
}
},"Action": [
"s3:ListBucket"
],"Resource": [
"arn:aws:s3:::MY_BUCKET_HERE"
],"Effect": "Allow"
},{
"Action": [
"s3:Getobject","s3:PutObject"
],"Resource": [
"arn:aws:s3:::MY_BUCKET_HERE/uploads/*","arn:aws:s3:::MY_BUCKET_HERE/public/*","arn:aws:s3:::MY_BUCKET_HERE/protected/${cognito-identity.amazonaws.com:sub}/*","arn:aws:s3:::MY_BUCKET_HERE/private/${cognito-identity.amazonaws.com:sub}/*"
],{
"Action": [
"s3:Getobject"
],"Resource": [
"arn:aws:s3:::MY_BUCKET_HERE/protected/*"
],"Effect": "Allow"
}
]
}
CognitoUnAuthorizedRole:
{
"Version": "2012-10-17","protected/*"
]
}
},"Resource": [
"arn:aws:s3:::MY_BUCKET_HERE/public/*","arn:aws:s3:::MY_BUCKET_HERE/protected/*"
],"Effect": "Allow"
}
]
}
所以,这是我的问题:
如果我使用带有放大库的 Storage.get 方法调用对象,我会毫无问题地获得图像。
但是,如果我在我的 LAMBDA 中这样做:
const { S3Client,GetobjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
const s3Client = new S3Client();
const command = new GetobjectCommand(params);
const url = await getSignedUrl(s3Client,command,{ expiresIn: 3600 });
return url;
lambda 返回 URL,但是当我从客户端获取此 URL 时,我收到拒绝访问错误。
MyLambda:
handler: functions/My_Lambda.handler
environment:
BUCKET: !Ref AssetsBucket
iamRoleStatements:
- Effect: Allow
Action: s3:Getobject
Resource: !GetAtt AssetsBucket.Arn
我不知道为什么会出现此错误...对于客户端,该库运行良好,但是如果我从 Lambda 尝试类似的操作,则它不起作用...
以下是有关标题的更多信息:
Response-headers:
HTTP/1.1 200 OK
x-amz-id-2: HERE_THE_VALUE
x-amz-request-id: HERE_THE_VALUE
Date: Sat,17 Jul 2021 21:10:06 GMT
Last-Modified: Sun,11 Jul 2021 19:28:42 GMT
ETag: "HERE_THE_VALUE"
Accept-Ranges: bytes
Content-Type: application/octet-stream
Server: AmazonS3
Content-Length: 1338
Request-headers:
GET /public/menu_icons/ADMINISTradOR.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIA4YRKNIM2VGLZX7UR%2F20210717%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210717T211004Z&X-Amz-Expires=900&X-Amz-Security-Token=IQoJ... HTTP/1.1
Host: ecommerce-gateway-develop-assetsbucket-72ahiv6louu0.s3.us-east-2.amazonaws.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Sec-GPC: 1
sec-fetch-site: cross-site
sec-fetch-mode: no-cors
Sec-Fetch-Dest: image
Referer: http://localhost:3000/
Accept-Encoding: gzip,deflate,br
Accept-Language: en-US,en;q=0.9
Response-headers:
HTTP/1.1 403 Forbidden
x-amz-request-id: HERE_THE_VALUE
x-amz-id-2: HERE_THE_VALUE
Content-Type: application/xml
transfer-encoding: chunked
Date: Sat,17 Jul 2021 21:10:04 GMT
Server: AmazonS3
Request-headers:
GET /public/menu_icons/ADMINISTradOR.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIA4YRKNIM2VU4GBIEB%2F20210717%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210717T211003Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJ.... HTTP/1.1
Host: ecommerce-gateway-develop-assetsbucket-72ahiv6louu0.s3.us-east-2.amazonaws.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,en;q=0.9
两个标头的某些部分是不同的...例如,LAMBDA 标头没有 ETag...我该怎么办?谢谢!
新更新
如果我从 lambda 的日志中获取 url,我会得到这个:
https://ecommerce-gateway-develop-assetsbucket-72ahiv6louu0.s3.us-east-2.amazonaws.com/public/menu_icons/REPORTES.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=xxxxxxIM22YARUSUJ%2F2xxxxx17%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210717T230538Z&X-Amz-Expires=3600&X-Amz-Signature=0a37f13e2a7axxxxf4d38cebxxxxxxxxx557c8805057ac6ddffe71c&X-Amz-SignedHeaders=host&x-id=Getobject
哪个效果很好。
然后,如果我转到网页并使用 Amplify 中的 Auth.SignIn
方法以用户身份登录,然后执行 Storage.get:
也很好用。
但是,如果我调用 lambda,现在 url 会更改:
现在这个网址有更多的参数...
这是我正在做的一个例子:https://github.com/MontoyaAndres/test_problem_s3_cognito
解决方法
我对您对现有系统的解释感到困惑(抱歉!),但一般方法是以下之一:
使用 Cognito
您的后端可以使用 Cognito 对用户进行身份验证,然后使用 AssumeRoleWithWebIdentity
返回一组凭据。然后,用户的客户端可以使用这些凭证根据分配的权限直接访问 AWS 服务。
例如,他们可能被允许访问自己在 Amazon S3 存储桶中的子目录,或从特定的 DynamoDB 表中读取。这可以通过将请求直接发送到 AWS 而不是通过后端来完成。
使用预签名网址
如果您的目标纯粹是授予对 Amazon S3 中私有对象的访问权限,那么而不是使用 Cognito,您的后端可以生成 Amazon S3 pre-signed URLs,提供对私有对象的限时访问对象。
每当后端生成包含对私有对象的引用(例如通过 <img src=...>
标记)的页面时,它可以执行以下操作:
- 应用通过检查应用数据库中的信息来验证用户是否有权访问私有对象
- 如果用户有权访问私有对象,后端会生成一个预签名的 URL
- 预签名 URL 在 HTML 页面中返回(甚至作为直接链接)
- 当 S3 收到预签名 URL 时,它会验证签名,如果正确,则返回私有对象
这种方法的好处是应用程序可以确定对单个对象的细粒度访问,而不是简单地使用存储桶和前缀来定义访问。这在用户之间基于每个对象共享数据(例如,用户可以与其他用户共享照片的照片共享应用)的情况下非常有用。
不要混用
在查看您的代码示例时,您的 Cognito 角色似乎授予对 S3 存储桶特定部分的访问权限:
arn:aws:s3:::MY_BUCKET_HERE/protected/${cognito-identity.amazonaws.com:sub}/*
然后,客户端可以使用其 Cognito 相关凭证直接访问存储桶的该部分。无需生成预签名网址。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。