sac Dahal
sac Dahal

Reputation: 1241

AWS. Storing and displaying the profile picture of users

I have a requirement of storing andd displaying the profile picture of my users. So I used the S3.upload function in my nodeJs backend to store the image. And after the image is stored I stored the link in database to fetch it using ng-source in my view. It worked but the link got expired after few hours and did not work. Below is the code for my upload. Is there any solution in how to do this or any other better way to do this.

   var body = fs.createReadStream(file.file.path);

      //Upload the photo to AWS

      s3.upload({Body: body}, function (err, data) {
        if (err) {
          res.sendStatus(500);
        }
        if (data) {

        //getSignedUrl and Store it in Database
          var AWS = require('aws-sdk');
          var url =  req.params.doctorId +  "/Images/"  + fileName;
          var s3 = new AWS.S3()
              ,params = {Bucket: S3Bucket, Key:url };
          s3.getSignedUrl('getObject', params, function (err, url) {
            if (err || url == null) res.status(500).send({msg: "amazon s3 error"});
            else if (url) {
              if(req.body.picture == 1) {
                User.findByIdAndUpdate(req.params.doctorId, {$set: {'FileName.profilePicture': url}},
                    function (err, doc) {
                      if (err)
                        res.sendStatus(500);
                      else
                        res.send({url: url});
                    });

Upvotes: 0

Views: 2845

Answers (1)

Karl Laurentius Roos
Karl Laurentius Roos

Reputation: 4399

This is because you're getting the URL from a signed URL and signed URLs expire by design.

From Share an Object with Others on AWS docs:

All objects by default are private. Only the object owner has permission to access these objects. However, the object owner can optionally share objects with others by creating a pre-signed URL, using their own security credentials, to grant time-limited permission to download the objects.

It seems like you're not exactly storing "secret" resources here that access has to be granted to, then the best approach here is store the image publicly. This is trivial to do and you simply have to set the ACL to public-read when you call PutObject or upload. That way you'll know the URL for the object without actually having to retrieve it:

https://s3-[region].amazonaws.com/[bucket]/[file]

This is what your upload statement would look like then:

s3.upload({ Body: body, ACL: 'public-read' }, function (err, data) {

Upvotes: 2

Related Questions