Проблема: как я могу успешно выполнить запрос файла 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