s3 上传可以在 sls 上离线工作,但在 sls 部署到真实的 aws api url 上后无法工作
在 sls 部署后,我获取端点 url 并尝试上传图像,但它在 s3.putObject 的 catch 块上给出访问被拒绝错误,但在 sls 离线本地上它可以工作,并且在 s3 存储桶中我可以看到文件,但部署后却不能上传和授予访问权限被拒绝。
部署后的真实 Api 与本地主机:
serverless.yml 如下
org: alvee
app: barikhojo-backend
service: barikhojo-backend
frameworkVersion: '3'
provider:
name: aws
region: ap-southeast-1
runtime: nodejs18.x
stage: dev
iam:
role:
statements:
- Effect: Allow
Action:
- "s3:*"
Resource: "arn:aws:s3:::${self:custom.imagesBucketName}"
- Effect: Allow
Action:
- 'dynamodb:PutItem'
- 'dynamodb:Get*'
- 'dynamodb:Scan'
- 'dynamodb:Query'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: "arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:custom.propertyTable}"
environment:
BUCKET_NAME: ${self:custom.imagesBucketName}
PROPERTY_TABLE: ${self:custom.propertyTable}
functions:
api:
handler: index.savePhoto
events:
- httpApi:
path: /
method: post
custom:
propertyTable: ${self:service}-property-table-${sls:stage}
imagesBucketName: ${self:service}-s3-${sls:stage}
resources:
Resources:
# S3 BUCKET
ImagesBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.imagesBucketName}
# Granting public access to bucket
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
ImagesBucketAllowPublicReadPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ImagesBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: AllowPublicReadAccess
Effect: Allow
Action:
- "s3:GetObject"
Resource:
- !Join ['/', [!GetAtt [ImagesBucket, Arn], '*']]
Principal: "*"
Condition:
Bool:
aws:SecureTransport: 'true'
# DynamoDB
PropertyTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.propertyTable}
AttributeDefinitions:
- AttributeName: ID
AttributeType: S
KeySchema:
- AttributeName: ID
KeyType: HASH
BillingMode: PAY_PER_REQUEST
plugins:
- serverless-offline
- serverless-plugin-common-excludes
lambda函数代码
const AWS = require('aws-sdk')
const parser = require("lambda-multipart-parser")
const { v4: uuidv4 } = require("uuid")
const s3 = new AWS.S3();
const BucketName = process.env.BUCKET_NAME;
async function saveFile(file){
try {
const savedFile = await s3.putObject({
Bucket: BucketName,
Key: `${file.filename}-${uuidv4()}`,
Body: file.content
}).promise()
return 'done'
} catch (error) {
return error
}
}
module.exports.savePhoto = async (event) => {
const {files} = await parser.parse(event)
const status = await saveFile(files[0])
return {
statusCode: 200,
body: JSON.stringify(
{
message: "Go Serverless v3.0! Your function executed successfully!",
input: 'File Uploaded',
bucketName: BucketName,
status: status,
filename: files[0].filename
},
null,
2
),
};
};
我认为您授予访问权限的 IAM 声明不完整。它仅授予对存储桶资源的访问权限,而不授予存储桶中的单个对象的访问权限。请参阅此处的文档了解如何定义它:https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html
tldr;您需要在末尾使用
/*
来指定资源
在本地工作可能是因为 IAM 检查根本没有在那里进行检查,或者您的凭证具有适当的权限