react-native-fast-image
react-native-fast-image copied to clipboard
Caching image with token (Amazon S3 bucket image)
I am trying to cache an image from Amazon S3 bucket, but this url has lots of variables. So I want to cache the image for only first part of url. Is it possible?
for an example: https://mybucket-dev.s3.ap-northeast-1.amazonaws.com/public/user/805327c1-8a64-4f94-a044-a2f158b2d677/feed/feed_20191117011738039.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2DSNUBOKIKRUQDRV%2F20191116%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20191116T174021Z&X-Amz-Expires=900&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEFIa
the first part of url always same: https://mybucket-dev.s3.ap-northeast-1.amazonaws.com/public/user/805327c1-8a64-4f94-a044-a2f158b2d677/feed/feed_20191117011738039.jpg
Can I use this part as a cache key? Thank you.
i think you can use headers
in source
. haven't quite made it work yet, but you'd need to split your presigned URL and decode the reserved characters, e.g. %2F
with decodeURIComponent.
I did but it doesn't work. Is there any example for it?
not that i could find, unfortunately. what does your errors say?
@junkdeck There is no error. Just it doesn't cache it. :/
how did you fetch the image using the header key? been trying at it without any luck for hours
Any updates here?
I have the same problem. Signed urls aren't cached. Is there any update on this?
Take a look here:
https://github.com/aws-amplify/amplify-js/issues/5296#issuecomment-609059682
You can supply the Authorization
header instead, and the url will remain static.
Take a look here:
aws-amplify/amplify-js#5296 (comment)
You can supply the
Authorization
header instead, and the url will remain static.
Hi Andrei,
I checked your getS3SignedHeaders
function but couldn't get how you create the signed headers. I realize you use aws-amplify
and some credentials in the client side.
Our client side application just has a url like this:
https://your-app.s3.eu-central-1.amazonaws.com/images/7_profileImage_1585830930973.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA5K5BXRHZTYRI6JJE%2F20200406%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20200406T132314Z&X-Amz-Expires=86400&X-Amz-Signature=b1c080c8b720532db082ded13699c26bfc4b2540ddebaaa668488d9cdb0d1bec&X-Amz-SignedHeaders=host&response-content-type=application%2Foctet-stream
Is it possible to generate signed headers using this url?
@boraikizoglu How are you generating the URL? As you can see it has an expiration date tied to it. Storing signed URLs in a database is not recommended.
The link I added shows a solution that takes advantage of Amazon Cognito based temporary credentials -> the signature is safe to be generated in the React Native app because the accesskey/secretkey/sessiontoken are tied to the currently logged in Cognito user. So, they're temporary and tied to the current user. AWS Amplify makes this easy.
If you cannot generate signatures client side one possible workaround is to set up an API function on your server which returns the set of signed headers based on server side AWS credentials, and then use those in your app to do the request.
@andreialecu, we don't store any signed URL in the database. They are generated in the server side each time user requests an image.
I finally managed to solve this issue.
Instead of sending pre-signed urls, like @andreialecu mentioned, send Authorization
headers which are created by your server.
I wrote a function which uses aws4
package to create signed headers. Hope this helps somebody.
import aws4 from 'aws4';
export function getURIWithSignedHeaders(imagePath) {
if(!imagePath){
return null;
}
const expires = 86400; // 24 hours
const host = `${process.env.YOUR_S3_BUCKET_NAME}.s3.${process.env.YOUR_S3_REGION}.amazonaws.com`;
// imagePath should be something like images/3_profileImage.jpg
const path = `/${imagePath}?X-Amz-Expires=${expires}`;
const opts = {
host,
path,
headers: {
'Content-Type': 'image/jpeg'
}
};
const { headers } = aws4.sign(opts, {accessKeyId: process.env.YORU_ACCESS_KEY_ID, secretAccessKey: process.env.YOUR_SECRET_ACCESS_KEY});
return {
uri: `https://${host}${path}`,
headers: {
Authorization: headers['Authorization'],
'X-Amz-Content-Sha256': headers['X-Amz-Content-Sha256'],
'X-Amz-Date': headers['X-Amz-Date'],
'Content-Type': 'image/jpeg',
}
}
}
Hi @boraikizoglu, is it working properly?
@randalb1991 it worked fine for me.
Hi, I tried the suggested solutions but nothing worked to me. Does anyone have another solution that worked?
Using the Authorization headers works with S3 signed URLs but I am using CloudFront which does not support inclusion of the signature info inside of Authorization headers. If you're using S3 directly (not through CloudFront) see here: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html
I am still dealing with this issue. I am using boto3
(in Python) on my backend, and I can't seem to find anything that generates the headers mentioned by boraikizoglu. If anyone could point me in the right direction, it would be much appreciated.
aws4
and react-native-aws4
are old packages.
How to do this with @aws-sdk/signature-v4
?
@roots-ai You can use whatever SDK you want to generate the URL signature on your server. You can make caching work once delivering the signed URL to your client by pulling the signature out of the query/URL parameters and including it in the Authorization header like this: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html
If you're using CloudFront signed URLs (instead of S3 directly) you can include the signature in a Cookie header instead: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-cookies.html
This repo caters for the above issue but still needs work: https://github.com/georstat/react-native-image-cache