Last active
May 13, 2016 17:35
-
-
Save kyptin/4898cd1068f09b893ddc to your computer and use it in GitHub Desktop.
S3 presigned URLs ready for image upload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns s3-presigned-url | |
"You can pre-sign an S3 path to allow users to access it without credentials. | |
This gives fine-grained access control with expiration to 'anonymous' (from | |
the perspective of S3) users. It's a convenient mechanism, if you can get it | |
to work. | |
There are some relatively well-trod paths for doing pre-signed S3 URLs, e.g. | |
when giving read-only access via an HTTP GET request. These paths have more | |
convenient and well-known mechanisms out there. | |
The code in this namespace is for a less common case: giving users | |
write access to a particular S3 location, e.g. if they upload their profile | |
picture. Unfortunately, to do this is a little more involved and requires | |
making greater use of the AWS Java SDK. I figured I'd publish this work in | |
case it was useful for others later. | |
For more information, here are some relevant resources: | |
- http://stackoverflow.com/a/23094964/202292 | |
- http://www.bennadel.com/blog/2693-uploading-files-to-amazon-s3-using-pre-signed-query-string-authentication-urls.htm | |
Note: for this code to work, be sure to include the `clj-time` and | |
`com.amazonaws/aws-java-sdk-s3` libraries in your list of dependencies. | |
-Jeff Terrell, Ph.D. | |
January 20, 2015 | |
[email protected] | |
https://github.com/kyptin" | |
(:require | |
(clj-time | |
[core :refer [days from-now]] | |
[coerce :refer [to-date]])) | |
(:import | |
(com.amazonaws.services.s3.model GeneratePresignedUrlRequest) | |
(com.amazonaws.services.s3 AmazonS3Client) | |
(com.amazonaws HttpMethod) | |
(com.amazonaws.auth BasicAWSCredentials) | |
(com.amazonaws.regions Region Regions))) | |
(def aws-region (Regions/US_EAST_1)) | |
(def access-key "your-access-key-here") | |
(def secret-key "your-secret-key-here") | |
(defn generate-presigned-url | |
"Create and return a S3 URL (as a string) that has been pre-authorized for a | |
PUT request with the given content-type. The URL expires in 1 day. | |
Ex: | |
(let [bucket \"my-avatars\" | |
s3-key \"The_Murder_Beard_2000.png\" | |
content-type \"image/png\"] | |
(presigned-upload-url bucket s3-key content-type)) | |
Returns: | |
\"https://my-avatars.s3-us-east-1.amazonaws.com/The_Murder_Beard_2000?AWSAccessKeyId=AKAI...&Expires=1421...&Signature=XD2b...\"" | |
[s3-bucket s3-key content-type] | |
(let [req (doto (GeneratePresignedUrlRequest. s3-bucket s3-key) | |
(.setContentType content-type) | |
(.setExpiration (-> 1 days from-now to-date)) | |
(.setMethod (HttpMethod/PUT))) | |
creds (BasicAWSCredentials. access-key secret-key) | |
region (Regions/US_WEST_1) | |
client (doto (AmazonS3Client. creds) | |
(.setRegion aws-region)) | |
url (.generatePresignedUrl client req)] | |
(str url))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note the tradeoffs in doing this approach (client self-uploading of images) versus uploading to a backend server that then stores the image in S3. This approach saves server resources and is perhaps quicker for the client, but it also gives no opportunity to the server to enforce size limits or know when (or even whether) an upload is complete (to generate thumbnails, for example). Some of these things could perhaps be done with AWS Lambda nowadays, but AFAIK the size limit is still not a capability of pre-signed URLs.