|
| 1 | + |
| 2 | +# Direct Upload to Amazon S3 |
| 3 | + |
| 4 | +This is a sample web site which shows how to use the Kendo UI Upload to store files directly in Amazon S3 buckets. |
| 5 | + |
| 6 | +Requires Kendo UI Version 2014.1.321 (internal build) and newer. |
| 7 | + |
| 8 | +See [Browser-Based Uploads Using POST](http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingHTTPPOST.html) from the AWS documentation. |
| 9 | + |
| 10 | +<!-- START doctoc generated TOC please keep comment here to allow auto update --> |
| 11 | +<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> |
| 12 | + |
| 13 | +- [Rationale](#rationale) |
| 14 | +- [Browser support](#browser-support) |
| 15 | +- [S3 Bucket Setup](#s3-bucket-setup) |
| 16 | + - [Security settings](#security-settings) |
| 17 | + - [CORS settings](#cors-settings) |
| 18 | +- [Server-side code](#server-side-code) |
| 19 | + - [Configuration](#configuration) |
| 20 | + - [Compatibility consideratinos](#compatibility-consideratinos) |
| 21 | +- [Client-side code](#client-side-code) |
| 22 | + |
| 23 | +<!-- END doctoc generated TOC please keep comment here to allow auto update --> |
| 24 | + |
| 25 | +## Rationale |
| 26 | + |
| 27 | +Uploading files directly to Amazon S3 has the following benefits: |
| 28 | + |
| 29 | +* Increased scalability |
| 30 | +* Reduced bandwith by a factor of almost 2x |
| 31 | +* Reduced server-side code complexity |
| 32 | + |
| 33 | +## Browser support |
| 34 | + |
| 35 | +This example is applicable to all [supported browsers](http://docs.telerik.com/kendo-ui/getting-started/web/upload/supported-browsers). |
| 36 | + |
| 37 | +## S3 Bucket Setup |
| 38 | + |
| 39 | +The destination bucket needs to be configured to accept browser-based uploads. |
| 40 | + |
| 41 | +### Security settings |
| 42 | + |
| 43 | +We highly recommend that you [create a new user](http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_SettingUpUser.html) with restricted permissions. |
| 44 | +The users [policy](http://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html) only needs to allow two actions on the destination bucket: *PutObject* and *PutObjectAcl*. |
| 45 | + |
| 46 | +Sample policy: |
| 47 | + |
| 48 | + { |
| 49 | + "Version": "2014-03-21", |
| 50 | + "Statement": [{ |
| 51 | + "Effect": "Allow", |
| 52 | + "Action": [ |
| 53 | + "s3:PutObject", |
| 54 | + "s3:PutObjectAcl" |
| 55 | + ], |
| 56 | + "Resource": "arn:aws:s3:::YOUR_BUCKET/YOUR_UPLOAD_ROOT/*" |
| 57 | + }] |
| 58 | + } |
| 59 | + |
| 60 | +> See [Managing IAM Policies](http://docs.aws.amazon.com/IAM/latest/UserGuide/ManagingPolicies.html) for full reference. |
| 61 | +
|
| 62 | +### CORS settings |
| 63 | + |
| 64 | +The destination bucket needs to be configured to accept (CORS)[https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS] requests from your application. |
| 65 | + |
| 66 | +This is done by uploading a CORS configuration file. This is the minimum configuration file required for this sample application: |
| 67 | + |
| 68 | + <CORSConfiguration> |
| 69 | + <CORSRule> |
| 70 | + <AllowedOrigin>http://localhost:62629</AllowedOrigin> |
| 71 | + <AllowedMethod>POST</AllowedMethod> |
| 72 | + <AllowedHeader>*</AllowedHeader> |
| 73 | + </CORSRule> |
| 74 | + </CORSConfiguration> |
| 75 | + |
| 76 | +> See [Enabling Cross-Origin Resource Sharing](http://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html) for additional considerations and full syntax reference. |
| 77 | +
|
| 78 | +The configuration can be uploaded using the AWS APIs or through the [Management Console](http://docs.aws.amazon.com/AmazonS3/latest/UG/EditingBucketPermissions.html) |
| 79 | + |
| 80 | +## Server-side code |
| 81 | + |
| 82 | +The main responsibility of the server-side code is to authorize uploads by creating and signing temporary policies for each client. |
| 83 | + |
| 84 | +The policy sets restrictions on the destination, content type and others. Any requests that don't match these rules will be rejected. The policy is signed with the secret key which is never transmitted to the client. |
| 85 | + |
| 86 | +> See [Policy Construction](http://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTForms.html#HTTPPOSTConstructPolicy) for additional details. |
| 87 | +
|
| 88 | +### Configuration |
| 89 | + |
| 90 | +The sample project needs to be configured before use. The options are stored in the `UploadS3\Controllers\HomeController.cs` file: |
| 91 | + |
| 92 | + var config = new S3Config { |
| 93 | + // Unique Policy ID and duration |
| 94 | + Uuid = Guid.NewGuid(), |
| 95 | + ExpirationTime = TimeSpan.FromHours(1), |
| 96 | + |
| 97 | + // Authentication |
| 98 | + AccessKey = "YOUR_ACCESS_KEY", |
| 99 | + SecretAccessKey = "YOUR_SECRET_KEY", |
| 100 | + |
| 101 | + // Bucket name and key prefix (folder) |
| 102 | + Bucket = "YOUR_BUCKET", |
| 103 | + BucketUrl = "http://YOUR_BUCKET.s3.amazonaws.com/", |
| 104 | + KeyPrefix = "YOUR_UPLOAD_ROOT/", |
| 105 | + |
| 106 | + // See http://docs.aws.amazon.com/AmazonS3/latest/dev/ACLOverview.html#CannedACL |
| 107 | + Acl = "private", |
| 108 | + |
| 109 | + // Mime type prefix |
| 110 | + ContentTypePrefix = "image/", |
| 111 | + |
| 112 | + // Fully qualified URL of an "empty document" in the same origin |
| 113 | + // Required for IE < 10 |
| 114 | + SuccessUrl = "http://localhost:62629/home/success" |
| 115 | + }; |
| 116 | + |
| 117 | +> Set the Acl value to `public-read` if you want to make resources publicly accessible. |
| 118 | +
|
| 119 | +### Compatibility consideratinos |
| 120 | + |
| 121 | +Older versions of IE (< 10) need to recieve a response from within the application in order to recognize successfull requests. |
| 122 | + |
| 123 | +The controller provides a "do nothing" action that simply returns an empty response: |
| 124 | + |
| 125 | + public ActionResult Success() |
| 126 | + { |
| 127 | + // Return empty response to signify success to IE < 10 |
| 128 | + return Content("", "text/plain"); |
| 129 | + } |
| 130 | + |
| 131 | +## Client-side code |
| 132 | + |
| 133 | +The client-side code appends all required fields before submitting the request to S3. This is done in the [upload](http://docs.telerik.com/kendo-ui/api/web/upload#events-upload) event handler: |
| 134 | + |
| 135 | + function onUpload(e) { |
| 136 | + var redirect = ""; |
| 137 | + |
| 138 | + if (typeof FormData === "undefined") { |
| 139 | + // Redirect to an empty page is required for IE < 10 |
| 140 | + redirect = "@ViewBag.S3Config.SuccessUrl"; |
| 141 | + } |
| 142 | + |
| 143 | + var file = e.files[0]; |
| 144 | + var type = mimeType(file.extension); |
| 145 | + |
| 146 | + e.data = { |
| 147 | + "key": "@ViewBag.S3Config.KeyPrefix" + file.name, |
| 148 | + "acl": "@ViewBag.S3Config.Acl", |
| 149 | + "Content-Type": type, |
| 150 | + "x-amz-meta-uuid": "@ViewBag.S3Config.Uuid", |
| 151 | + "AWSAccessKeyId": "@ViewBag.S3Config.AccessKey", |
| 152 | + "Policy": "@ViewBag.Policy", |
| 153 | + "Signature": "@ViewBag.PolicySignature", |
| 154 | + "success_action_redirect": redirect |
| 155 | + }; |
| 156 | + } |
| 157 | + |
| 158 | +> Important: Existing files will be overwritten. It's highly recommended to make file names unique. |
| 159 | +
|
| 160 | +All fields except "Content-Type" are taken directly from the configuration. |
| 161 | +The content type is inferred from the extension. |
| 162 | + |
0 commit comments