In this
series of posts, I am writing about various AWS services. In my previous posts,
I have written about AWS EC2, Elastic Load Balancing, Auto Scaling, DynamoDB,
Amazon Simple Queue Service and Amazon Simple Email Service.
In my
last post, I have added an user activation functionality to my digital card
store application. The application is used for managing digital cards. So far I
have added, user registration, user session management, selling and buying
cards and user activation functionality. The user can add a new card by
specifying a name only.
In this
post, I will add an upload function that allows user to attach an image to a digital
card. I will use Amazon S3 to store uploaded image files.
Upload Functionality
When we
think about uploading a file, the first option that comes to mind is to upload
the file to an EC2 instance from the browser and then send the file to Amazon
S3 from the EC2 instance.
While
this method accomplish the image upload requirement, there is a better method.
In 2012, Amazon announced CORS
support for Amazon S3, which allows any web application to upload files to
S3 directly. This allows quick and efficient uploads and eliminates proxying the
upload requests.
The
picture below shows the upload process.
To use direct
uploads to S3, we should follow the steps below.
1.
Enable CORS support for the bucket.
2. Configure
access permissions.
3. Develop
the signing part in server
4.
Prepare the web front end.
In this
post, I will start with the code from my last
post. The code can be found here. In the
post that I have written about DynamoDB, I have generated the Card entity
class with imageURL field. In this post, I will use this field to hold the URL
of the uploaded image file. There will be no change in entity class and
CardController class. After the image uploaded to the S3, its url will be
passed as imageURL to add card request. The card will be persisted with this
url to DynamoDB and it will be used as card image url to show the card image in
the card listing table. The final code for this post can be found here.
Let's
start.
1. Enable CORS support for the bucket
To be
able to use direct uploads from any web application, the target S3 bucket
should be configured to allow requests from a different domain. For more
information, see S3 Cors
documentation.
To enable
CORS support using Amazon Console, use the steps below. To use AWS CLI, see
here.
- · Login to Amazon Console and select S3
- · Select your bucket and click Properties
- · Click Permissions and then click Edit CORS Configuration
- · Paste the below configuration and click Save and then click Close.
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Please note that I allowed any
origin to post to the bucket for easy development. To provide robust securiy in
production use, please restrict the domains accordingly.
2. Configure access permissions
To
allow uploads to the S3 bucket, the bucket should be writable. There are a few options
for this. The first option is to make the bucket public. But if you make the
bucket public, everybody can write to your bucket and you take the risk of
uncontrolled uploads. The second option is to make the bucket writable by a
specific IAM user and sign the upload requests with this users credentials.
This option is more secure compared to first option. In this post, I will use
the second option. Please consider security options before using the upload
function in production.
While
using signed requests, S3 expects your upload requests to include an upload
policy and a signature. The signature is prepared using your IAM credentials.
You can use any IAM credentials, but to provide more strict security, please
use a dedicated IAM user for this purpose that have write access only to the
target S3 bucket. This way, you can be sure that in case of a credential
disclosure, it affects only a specific S3 bucket, not any other AWS resources. For
more strict security, you can use Temporary
Security Credentials.
To configure access permissions using Amazon Console, use the steps below. To use AWS CLI, see here.
- · Login to Amazon Console and select S3
- · Select your bucket and click Properties
- · Click Permissions and then click Edit bucket policy.
- · Paste the below policy and click Save
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXX:user/mys3user"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::mys3bucket/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXX:user/mys3user"
},
"Action": "s3:PutObjectAcl",
"Resource": "arn:aws:s3:::mys3bucket/*"
}
]
}
This
policy allows our IAM user to upload the file and set its access level to make
it readable to everyone (public-read). We make the uploaded files publicly
readable so the browser can show the card images directly from S3 when listing
cards. If you don't want to make the images public, you can generate temporary
signed image urls to show card images in the browser. You can find more
information here.
3. Develop the signing part in server
First
we create Spring controller to generate signature. The class use bucket name,
bucket region, AWS credential for signing the bucket uploads and the secret of
the AWS credential as variables. After generating the signature, the controller
returns the signed upload data that will be used in upload request.
@RestController
public class CardUploadController {
@Value("${user.card.upload.s3.bucket.name}")
String s3BucketName;
@Value("${user.card.upload.s3.bucket.region}")
String s3BucketRegion;
@Value("${user.card.upload.s3.bucket.awsId}")
String s3BucketAwsId;
@Value("${user.card.upload.s3.bucket.awsSecret}")
String s3BucketAwsSecret;
@RequestMapping(value = "/presign", method = RequestMethod.POST)
@ResponseBody
public PreSignedS3UploadData presignS3Upload(@RequestParam("contentType") String contentType, @RequestParam("fileName") String fileName, HttpSession session) {
PreSignedS3UploadData res;
try {
String extension = fileName.lastIndexOf('.') == -1 ? "" : fileName.substring(fileName.lastIndexOf('.'));
String s3FileName = "upload_" + (int)(100000 * Math.random())
+ extension;
res = S3SignUtil.generatePreSignedUploadData(s3BucketName, s3BucketRegion, s3BucketAwsId, s3BucketAwsSecret, contentType, s3FileName);
}
catch (Exception e) {
res = new PreSignedS3UploadData("Can't generate signature for
upload: " + e.toString());
}
return res;
}
}
The
signature generation algoritm first generates a security policy, then generates
a signing key with AWS credentials and then signs the policy with the signing
key. The security policy specifies the expiration date and time, ACL for the
file being uploaded and some other options. This application generates a policy
with 3 minute expiration time, public-read ACL to allow public access and 1MB
max upload size. A sample policy looks like below.
{
"expiration": "2017-04-26T23:09:59.638Z",
"conditions": [
{ "acl": "public-read" },
{ "bucket": "XXXXX" },
{ "key": "upload_49921.jpg" },
{ "Content-Type": "image/jpeg" },
["content-length-range", 0, 1048576],
{ "x-amz-credential": "XXXXXXXX/20170426/eu-central-1/s3/aws4_request" },
{ "x-amz-algorithm": "AWS4-HMAC-SHA256" },
{ "x-amz-date": "20170426T000000Z" }
]
}
Policy and
signature generation code is in S3SignUtil class.
For
more information on generating the policy and signature, see here.
4. Prepare the web front end.
After
we complete the code that generates the signed upload data, we can prepare the
web front end. We will change the dashboard.jsp file and add a file upload input
to the Add Card form. When the selection change in the file upload input, we
generate a signature using the controller we created in the 3rd step. Then we
generate a dynamic form to post the file with the signature to the S3 bucket
url.
The
script is below.
function cardImageFileUpdated(){
var file = document.getElementById('cardImageInput').files[0];
if (file != null)
startCardImageFileUpload(file);
}
function startCardImageFileUpload(file) {
$.ajax({
type: "POST",
url: "presign",
data: 'contentType=' + encodeURIComponent(file.type) + '&fileName=' + encodeURIComponent(file.name),
success: function(data){
if (data.errorMessage)
alert(data.errorMessage);
else
doCardImageFileUpload(file,
data);
},
});
}
function doCardImageFileUpload(file, data){
var formData = new FormData();
formData.append('key', data.fileName);
formData.append('acl', 'public-read');
formData.append('Content-Type', data.contentType);
formData.append('X-Amz-Credential', data.credential);
formData.append('X-Amz-Algorithm', "AWS4-HMAC-SHA256");
formData.append('X-Amz-Date', data.date);
formData.append('Policy', data.policy);
formData.append('X-Amz-Signature', data.signature);
formData.append('file', $('input[type=file]')[0].files[0]);
$.ajax({
url: data.bucketUrl,
data: formData,
type: 'POST',
contentType: false,
processData: false,
success: function () {
var imageUrl = data.bucketUrl + "/" + data.fileName;
document.getElementById('cardImagePreview').src = imageUrl;
document.getElementById('cardImageUrl').value = imageUrl;
},
error: function () {
alert("Upload error.");
}
});
}
And we change the Add Card form from
<form id="add-card-form" onsubmit="return false;">
<input type="text" name="name"
placeholder="name" />
<button onclick="addCard()">Add</button>
</form>
to
<form id="add-card-form" onsubmit="return false;">
<span>Card Name</span>
<input type="text" name="name"
placeholder="name" /><br/>
<span>Card Image File</span>
<input type="file" id="cardImageInput"
accept="image/*" onchange="cardImageFileUpdated()"/>
<img style="border:1px solid gray;height:160px;width:120px;" id="cardImagePreview" src="/images/default-card.png"/>
<input type="hidden" id="cardImageUrl"
name="imageUrl" value="/images/default-card.png"/> <br/>
<button onclick="addCard()">Add</button>
</form>
First we
add an input with file type to select the image file. And we use an image tag to
preview the image after the upload complete. And then we add a hidden imageURL
field to Add Card form as I talked in the beginning of this post.
At this
point, we finished the uploading the card image to S3 and saving the card with
the url of the file uploaded to S3. Next we will show the image of the cards in
card listing tables. We change the buildHtmlTable JavaScript function in
dashboard.jsp from
if (cellValue == null) cellValue = "";
row$.append($('<td/>').html(cellValue));
to
if (cellValue == null) cellValue = "";
if (columnList[colIndex] == 'imageUrl')
cellValue = '<img
style="border:1px solid gray;height:160px;width:120px;" src="' + cellValue + '"/>';
row$.append($('<td/>').html(cellValue));
to use the imageURL
field as card image.
After
showing the card images in card listings, we have completed the changes. If you
run the application with this command,
$ mvn spring-boot:run
-Drun.jvmArguments="-Duser.activation.queue.name=XXX -Dmail.from.address=XXX
-Duser.card.upload.s3.bucket.name=XXX -Duser.card.upload.s3.bucket.region=XXX -Duser.card.upload.s3.bucket.awsId=XXX
-Duser.card.upload.s3.bucket.awsSecret=XXX"
you can
use the application like the screenshots below.
Summary
In
this post, I have shown adding a file upload functionality to add card images.
I have used direct S3 uploads from the browser without uploading the file to a
EC2 instance first. The code can be found at my GitHub repository.
In
my next posts, I will continue to use various AWS services to add functionality
to my digital card store application.
Nice article, users are attracted when they see your post thanks for posting keep updatingAWS Online Training Hyderabad
ReplyDeleteI was barely amazed at how you had written this content. Please keep posting.
ReplyDeletesoftware testing selenium training
selenium testing training in chennai
Best selenium training in chennai
Cloud Certification in Chennai
Cloud Courses in Chennai
Cloud Computing Classes in Chennai
Thanks for your sharing such a useful information. this was really helpful to me.
ReplyDeleteHacking Course in Bangalore
Hacking Training in Adyar
Ethical Hacking Training in Tambaram
Good job! Fruitful article. I like this very much. It is very useful for my research. It shows your interest in this topic very well. I hope you will post some more information about the software. Please keep sharing!!
ReplyDeleteWeb Designing Training Institutes in Chennai
Web Designing Course in Chennai with placement
website design courses
web design classes
Web Designing Training Centers in Chennai
web design training chennai
Very impressive blog! I liked it and was very helpful for me. Thanks for sharing. Do share more ideas regularly.
ReplyDeleteSpoken English Classes in Chennai
Spoken English Classes in OMR Chennai
Spoken English Classes near me
Spoken English Classes near Thoraipakkam
Spoken English Classes in Sholinganallur
Spoken English Classes in Padur
Best Spoken English Classes in Chennai
ReplyDeleteThanks for your information, the blog which you have shared is useful to us.
php training center in coimbatore
php training in coimbatore
best php training in coimbatore
php course in coimbatore
best php training institute in coimbatore
Thanks for sharing this valuable information to our vision. You have posted a worthy blog keep sharing.
ReplyDeletedailyconsumerlife
Guest posting sites
Thanks for sharing this valuable information to our vision. You have posted a worthy blog keep sharing.
ReplyDeleteTOEFL Coaching in Chennai
TOEFL Training in Chennai
TOEFL Classes in Chennai
TOEFL Coaching Centres in Chennai
TOEFL Centres in Chennai
TOEFL Coaching Classes in Chennai
TOEFL Course in Chennai
Best TOEFL Coaching Institute in Chennai
Thank you for taking the time and sharing this information with us. It was indeed very helpful and insightful while being straight forward and to the point.
ReplyDeleteDigital Marketing Course in Chennai
Digital Marketing Training
Digital marketing training institute in chennai
Digital marketing classes
Best digital marketing course in chennai
Digital marketing course chennai
You have done an excellent job by posting this. Thank you for sharing this with us
ReplyDeleteSpark Training Academy | Spark Training in Chennai | Apache Spark Certification | Spark Training in Adyar | Spark Training in Velachery | Spark Course in Tambaram
Very impressive blog! i liked it and was very helpful for me.Thanks for sharing. Do share more ideas regularly.
ReplyDeletePHP Training in Chennai Velachery
PHP Training in Saidapet
PHP Training in Aminjikarai
PHP Training in Sholinganallur
PHP Training in Padur
PHP Training in Kandanchavadi
Thanks for your efforts in sharing the knowledge to needed ones. Waiting for more updates. Keep continuing.
ReplyDeleteHacking Course in Bangalore
Learn Ethical Hacking in Bangalore
Ethical Hacking Course in Adyar
Ethical Hacking Course in Nolambur
Ethical Hacking Training in Chennai Velachery
Ethical Hacking Training in Aminjikarai
Thank you for your information.it is very nice article.
ReplyDeleteAWS Online Training
Hi,
ReplyDeleteI must appreciate you for providing such a valuable content for us. This is one amazing piece of article. Helped a lot in increasing my knowledge.
Selenium Training in Chennai
Best selenium training in chennai
iOS Training in Chennai
Digital Marketing Training in Chennai
.Net coaching centre in chennai
Selenium Interview Questions and Answers
Different functions in testing
Loadrunner Training in Chennai
Loadrunner Training
Thank you for updating such an informative content. I Sugessed SLA for the Best Software Training in Chennai with 100% Placement. Offering Courses are AWS Training Course,Hardware and Networking Training, Advanced Excel Training, Machine Learning Training in Chennai, etc.,.
ReplyDeleteReally awesome blog. Your blog is really useful for me
ReplyDeleteRegards,
Data Science Course in Chennai
Thanks for providing wonderful information with us. Thank you so much.
ReplyDeleteRegards,
Data Science Course in Chennai | R Programming Training in Chennai | Python Training in Chennai
Your post is just outstanding !!! thanks for such a post, its really going great work.
ReplyDeleteData Science Training in Chennai | Data Science Course in Chennai
nice course. thanks for sharing this post.
ReplyDeleteAWS Training in Delhi
The post you published is full of useful information. I like it very much. Keep on posting!!
ReplyDeleteRPA Training in Chennai
RPA Course in Chennai
Python Training in Chennai
SEO Training in Chennai
Software Testing Training in Chennai
Java Training in Chennai
Web Designing Course in chennai
RPA Training in Tnagar
This comment has been removed by the author.
ReplyDeleteThanks for giving great kind of information. So useful and practical for me. Thanks for your excellent blog, nice work keep it up thanks for sharing the knowledge.
ReplyDeleteAWS Training in Chennai | AWS Training Institute in Chennai
Clinical sas training in chennai | SAS Training course chennai
ReplyDeleteI have to voice my passion for your kindness giving support to those people that should have guidance on this important matter.
This comment has been removed by the author.
ReplyDelete"Thanks for sharing this information with us...
ReplyDeleteDigital Marketing Training Course in Chennai | Digital Marketing Training Course in Anna Nagar | Digital Marketing Training Course in OMR | Digital Marketing Training Course in Porur | Digital Marketing Training Course in Tambaram | Digital Marketing Training Course in Velachery
"
Pretty blog, so many ideas in a single site, thanks for the informative article, keep updating more article.
ReplyDeleteDigital Marketing Training Course in Chennai | Digital Marketing Training Course in Anna Nagar | Digital Marketing Training Course in OMR | Digital Marketing Training Course in Porur | Digital Marketing Training Course in Tambaram | Digital Marketing Training Course in Velachery
Hey!Amazing work. With full of knowledge. Our Team resolve any glitches occurring while utilizing the software. Looking for solution of Quickbooks Error 1712 Contact us +1 877 751-0742 .Our experts will assist you to fulfil your accounting needs. The solutions are accurate and time-saving.
ReplyDeleteAn awesome blog thanks a lot for giving me this great opportunity to write on this.
ReplyDeleteVé máy bay Vietnam Airline tu Dai Loan ve Viet Nam
combo đi quy nhơn 4 ngày 3 đêm
combo đà lạt 3 ngày 2 đêm 2021
combo đi vinpearl nha trang
combo du lịch phú quốc
Hey! Nice Blog, I have been using QuickBooks for a long time. One day, I encountered QuickBooks Customer Service in my software, then I called QuickBooks Customer Servicet. They resolved my error in the least possible time.
ReplyDelete