Проблема: как я могу успешно выполнить запрос файла PUT на предварительно подписанный URL-адрес, в котором корзина имеет следующие разрешения:
- Блокировать публичный доступ = отключено для всех 4 опций
- Список контроля доступа = публичное чтение
- Политика сегмента = пусто
- Конфигурация CORS = PUT
Вот конкретный пример того, что я сделал …
Я выполнил POST для своей presign
конечной точки …
> POST /dev/presign HTTP/2
> Host: 9xugkdzvch.execute-api.ap-southeast-1.amazonaws.com
> user-agent: insomnia/2020.2.2
> content-type: application/json
> accept: */*
> content-length: 51
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
| {
| "name": "profile_1.png",
| "type": "image/png"
| }
он вернулся
{
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true
},
"body": {
"error": false,
"data": "https://profilephoto-upload-dev.s3.ap-southeast-1.amazonaws.com/profiles/profile_1.png?AWSAccessKeyId=ASIA4IWFXQ2GLT2FGUUA&Content-Type=image%2Fpng&Expires=1593475190&Signature=JO4pNtbXmb56OYiClZhil4hse0c%3D&x-amz-meta-username=foobar&x-amz-security-token=IQoJb3JpZ2luX2VjEIj%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDmFwLXNvdXRoZWFzdC0xIkcwRQIhAP5kW%2Fj6Y5BiLgAhec3w6bv17CL8QuEabOy7hhhtK81JAiA7pS6IkGE3WtnIcD78%2BOytl1luSdLBkI9fg%2F2GzxpApirUBQghEAAaDDg0MzMwMjAxMjU1NiIMdbMwBimx3k0miN5lKrEFfUAFtMJep90tfYQqwW09Od1HTSaUKkVUqP0eOaQg89vEnplJ%2BCQwKopOF8Ed8AiFAFQ9qJcbtmg39wEqIBa5Z0oOdfDEphRXDmVWX%2BCQvdCCoPbbZeaK2tBg4PN2f%2FL8OBa4AebUMCwnVJVneA7Pf5p7hVKKeP%2BePDfMWYOpChS9smp0UjfoVSKYDDA1GDS4eE%2FTN02KjnLdVOWPqoAOm%2FurDzbs%2FYe8B2xnC6R0%2FpbMrj2j59bHB9d8f2GcKXOfiHpeKff%2BLNYYsSmEAApsiW2N05ZMTAWBZQTUyWy53jFhYrZU11uo8RlzKoJOiI6pNoufk4CtbdtVYLxdvQZuxQm7TRJNMLDAQQcL6qR07N0sxHMeo7IIe5QNLT%2B%2FUwqG4X3FJxhYHnSvP7CRT%2FtlS%2Fxutl3rNpthpxDplRBDMtc5rSig6H%2Bb9O1vFZKAG%2B%2F9J%2BE4sCWfckh7kANCYA%2BY3bDHvkTj%2BKKWckzpQB4yLyPD4L%2FbiUDm9T520C9ROwXXhMAun%2BI2hxidauOTkyx%2Bzny5M8zTMN8gvVcxlIHgQHCYy6776WdI2qk%2FmKxYM814s74zt4o3AhtIDTJfEJV0NriqcwxOzZqsnGXPBP9fxri5t57M%2B%2BeONpjcFJpRhj%2B1Os1omCe3CL1R84RsrVPfc8FzGu12yM15FeI0Qb5duqgH3kWdc6wEflRsGPWPfVqHdWfj8euhGQXwsE2m4tcglZdYCpxWfMnbF%2Foz8TOJv9b3ODFrYNTtaeG9arUbLZ8CPqWH8Nyag4MNRgZAZRJNHbc4eBKqi9YHp1p%2FCillnFgmoPMwccyziv%2BGAPkjtS9KCLb0XWEwJwJLgLWNllVka9g%2BlODt6HK2mPb0zPLpsQuDI5qQwnBlSWPbhqwpoWyatvmV7aPaeF3dJm5yBVKAMyAwqPbp9wU6zQLBnlCtwUNRh0HMSUwfPWoFlpweESBTUzjEQFRui7g874ksQtlF51dpUsdXF7JI1kV%2FWr8A%2BxhxlMEjxyhoTj70hUVO7V55I7Ppx3Iyz5AlBAoh2nu4NZccHY4JYjU3de%2FYWVa0jfBSxP0WU%2F5GHbwbENjCpgEMhpDVcFf409UN8ecQi53nQh8ytjsDJMTwYalBM8ys1BfXdvLMkL2dtBFTfHtVjIGtrOkTxfH3CtbT24CzAtWrXxBCY%2BDd97o3oi6ztloybTJtxhI8Zdb6vojsFm95QVmVAVO5PaeZ%2BgHOoqHFHJ%2BXG1kbV8OexmT1S1bAXuu%2Fa07HDjJzqBYovvzWa%2BaG9pG8SKiw0N%2Bb5mdxMDdcGEqVIMwUK7mf7sY06Z%2Fbl1SQvErfpEsgA67C1Qtrgb0fKetVMlQR4Zq%2F53H%2FrFrys2OAnPXUfVLiqWY%3D",
"message": null
}
}
Затем я использовал URL-адрес в data
для выполнения запроса PUT, и он не удался с AccessDenied
PUT /profiles/profile_1.png?AWSAccessKeyId=ASIA4IWFXQ2GPP2VWPFE&Content-Type=image%2Fpng&Expires=1593513254&Signature=vmXn5%2Fk%2Bk3hh98B8OeNlU%2F8XetY%3D&x-amz-meta-username=foobar&x-amz-security-token=IQoJb3JpZ2luX2VjEJL%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDmFwLXNvdXRoZWFzdC0xIkcwRQIhAK6oeGhiy%2BuWwonWYViWa5pzJxZlSwB5MWjuLcZas6NvAiBmArs%2B8noZacruG0dlWrUyIUm30WFLKUYACVW2xMCFmyrUBQgrEAAaDDg0MzMwMjAxMjU1NiIMgQFekIbk3lBaS%2BmyKrEFBrdMyiCwa1iKVcgFxO%2BW1RTCu5M9aKotfJtBCxtW8gGkUY8VsMsVLPYUDWrJU07z7QjdRIK5xR3%2BdWtkK%2FvW6ZULjqrtVwiDbwnncug7FvvzWBCzc2oOVUFenSBNXhr%2FGnlCbqk6mFyqkOtCeFffOYtls19tU56GsSa1aaTwdwQcRld02G1TJCgj6egjgxSoHqDFbntlHU84vWcW5wi1O4YX4NwAEhWmiLC%2BU6RsfbR0NA%2BzJHlRGShJhEAY1pxOmm3533DAzSjlhj3yvTJN8whT4jFUEvn0jWFCLb3u9rC99%2FwjgtPH0jlU%2BqESTP0VlATuCU%2F5by1iTyX4TLRFyF0vCqx5%2BEePH0SdZeVDEqi%2BIgXIkOGG8fzJQkxLu536uCioSojmRYqiG16Osu9mAiP08LEGsIquzsIoIZmWve3P56gwk0pM28TWYz%2BhZtynJCXAIDOtm1gZ7j14ho1SrpIazM6fJ95NgmuqJfud%2BIGbXdytPZQj1jRsj2fH3vlw66LTXN6AKBVPy6yTf45fMBfP2mywSZwkQtjEQ6hVN76nKD6Z1jZ%2F2Pbk%2FpFUwtcfYbGeKDIEpnV6h2%2BvsiaaNmos9eIYLkt6R9glYvInnIYvp6TOKJoicZgv%2BChr1lY8L728wCXnKLXxHTnv1YTnE5z%2FmtMbG4ZxYkj0ioaJt6kS2%2B3Lh%2BXdrbnwK7gbn3rFGT9EaTyeLSOymIB%2BHzAAfxB902g0c4jV6Em6B9xUxUgfXjHY1I5Gla1t36lEgAe7rlfngUlhoomJjDpMCw4IbzFnjvjXdAIzj7cJjmY%2FPxhdy4gp3pRvcgTkJ%2BV9DV8x2vMSgZS1qX5v%2FMQ%2BSQLStK5aY%2FjKqYkBt03102M1NovHpYiaV4XdE6%2F53unpdEyKtsKjUwYGLebd21kUhHkfoX4woqPs9wU6zQJwdh2wOJcRW9Wp6GmVLOyxfI23RxkAgygOjN5R1AUr%2F%2BehPrSr9iQsYjI%2FWzJqi7Ohzr3kZqjXuL4Yi1UKyRF6vyKckSDMQb371HypXkopMuoPxmNpZqI42IwO8%2BM0ktrJfnJ7Kp4i3EDw9eujy6Cuau5fsD8v6s0c3m5hNu1gmESfdmZr1%2BR%2FCVbifqgeLLwyGak96UyO%2BapQ4kOU6tu5uNskL1ewx%2F2K0esKq6qEz1IXA%2Fx5n5dioiom3GI9QVRfrtF7Z%2BhqBLipVfHMR2Pb4N3egoqBj80ux9u0UzYZ8rLst7Ns0tlJzmCHGxh0py9M7kUPAQmVMdQE4rAlP2FjMQiMWpOCiqo4uwADjKrlwinhSc98LPGYTxJ%2F8QveSfixbeZmgdC1gJkOAMUEdgnoh%2BeRB1dHR%2B3SavrFp1EIudMDIUxd4AxZSDYN%2F%2FY%3D HTTP/1.1
> Host: profilephoto-upload-dev.s3.ap-southeast-1.amazonaws.com
> User-Agent: insomnia/2020.2.2
> Content-Type: image/png
> Accept: */*
> Content-Length: 578256
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>A6037105527AC3DE</RequestId>
<HostId>KqRDTOrRWDTjnQesY9ZIbBb95/lmqLmro7YLETogaA6qu4n0Jq8znwtExBxdpjDhgXr2Lg/MyqU=</HostId>
</Error>
Для данного: Вот мой presign
код …
import S3 = require("aws-sdk/clients/s3")
import * as mime from "mime"
const createPresignedPost = async (key: string, contentType: string): Promise<string> => {
const s3 = new S3()
const params: S3.Types.PutObjectRequest = {
Bucket: "profilephoto-upload-dev",
Key: `profiles/${key}`,
ContentType: contentType,
Metadata: {username: "foobar"}
}
return s3.getSignedUrlPromise("putObject", params)
.then(some => {
console.log(`returned: ${some}`)
return some
})
}
app.post('/presign', async (req, res) => {
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true
}
try {
const key = `${req.body['name']}`
const mimeType = mime.getType(req.body['name'])!
const presignedPostData = await createPresignedPost(key, mimeType)
res.status(200).send({
statusCode: 200,
headers,
body: {
error: false,
data: presignedPostData,
message: null
}
})
} catch (error) {
console.trace(JSON.stringify(error))
res.status(500).send({
statusCode: 500,
headers,
body: {
error: true,
data: null,
message: error.message
}
})
}
})
Этот экспресс-маршрут принадлежит созданной здесь лямбде …
presignedpostdata:
handler: ${self:custom.${self:custom.stage}.handler}
role: arn:aws:iam::843302012556:role/service-role/auto_presignedpost_dev-role-w7qof39g
events:
- https:
path: /presign
method: post
cors: true
Упомянутая роль ARN имеет эти разрешения …
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::profilephoto-upload-dev/*"
},
{
"Sid": "VisualEditor2",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "*"
}
]
}
наконец, ведро S3 создается вот так …
ProfilePhotoBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: profilephoto-upload-${self:custom.stage}
AccessControl: PublicRead
CorsConfiguration:
CorsRules:
- AllowedHeaders: ['*']
AllowedMethods: ['PUT']
AllowedOrigins: ['*']
Я не копался глубоко в вашем коде, но думаю, вам нужны соответствующие заголовки auth в вашем запросе PUT. Подписанного URL-адреса недостаточно. — person deemonzter schedule 30.06.2020
@ Брэд, не могли бы вы указать мне правильное направление, о чем appropriate auth headers
ты говоришь? — person deemonzter schedule 30.06.2020
Я проверю позже … У меня есть код, успешно использующий PUT от клиента. Если подумать, я могу использовать только заголовки, потому что я также указываю x-amz-acl
и Cache-Control
. Один или оба из них не могут быть установлены в подписанном URL-адресе. — person deemonzter schedule 30.06.2020
@Brad, спасибо. Я действительно с нетерпением жду рабочего примера, потому что у меня заканчиваются идеи, как пройти через AccessDenied … AWS не предоставляет никаких полезных журналов ни на стороне консоли AWS … — person deemonzter schedule 30.06.2020
Если вы можете показать фактический запрос и ответ HTTP PUT, это будет полезно. — person deemonzter schedule 30.06.2020
@Brad обновил мой пост запросом PUT (проверьте выше). Это просто простой запрос PUT, указывающий на заранее подписанный URL-адрес с полезной нагрузкой файла. — person deemonzter schedule 30.06.2020
Я считаю, что проблема в том, что вы должны использовать
s3.createPresignedPost
вместоs3.getSignedUrlPromise
, а затем вы должны использовать метод POST, а не PUT при отправке запроса.Я думаю,
s3.getSignedUrlPromise
требует, чтобы вы предоставилиBody
объекта во время подписания запроса, аs3.createPresignedPost
разрешает отправку любого тела. Сs3.createPresignedPost
вы также можете добавитьConditions
для выполнения определенных действий, например ограничить максимальный размер объекта.Видеть:
Я могу попробовать вариант публикации … но чего я не понимаю, так это предоставления
body
объекта во время подписи, поскольку это создает большие накладные расходы для функции подписи — person deemonzter; 30.06.2020Определенно не использовать для этого метод POST формы. Вы можете использовать PUT URL, вам просто нужны правильные заголовки. — person deemonzter; 30.06.2020