S3ファイルをアップロードして Signed URL (時間制限でアクセス可能なURL)を取得してみます。
S3にアップロードされたオブジェクトは(IAMアカウント等の設定を行わない限り)基本的に全公開か非公開となり、オブジェクト単位での公開/非公開の設定はできません。
しかし、Signed URL を取得することによって、時間制限付きで任意のオブジェクトを公開することができます。
今回は Go の goamz ライブラリを使ってファイルのアップロードから Signed URL の取得までを行ってみます。
仕様
- 同じ階層にある
images
ディレクトリの中の画像ファイルをS3へアップロードする - ファイル名は SHA256 のハッシュ値に変換する
- Signed URL を構造体に詰めて返す
コード
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/goamz/goamz/aws"
"github.com/goamz/goamz/s3"
)
type SignedURLResponse struct {
URL string
}
var image_exts = []string{
"bmp",
"gif",
"jpeg",
"png",
"tiff",
}
func IsImageFile(file []byte) (bool, string) {
mime := http.DetectContentType(file)
s := strings.Split(mime, "/")
if len(s) < 2 {
return false, ""
}
for _, ext := range image_exts {
if ext == s[1] {
return true, mime
}
}
return false, ""
}
func GenFileHash(file []byte) string {
h := sha256.New()
h.Write(file)
bs := h.Sum(nil)
return hex.EncodeToString(bs)
}
func S3Upload(bucket *s3.Bucket, dir string) {
wg := new(sync.WaitGroup)
fs, _ := ioutil.ReadDir(dir)
for _, f := range fs {
wg.Add(1)
go func(inner_f os.FileInfo) {
buf := make([]byte, inner_f.Size())
img, _ := os.Open(dir + "/" + inner_f.Name())
defer img.Close()
img.Read(buf)
is_image, mime := IsImageFile(buf)
if is_image {
filename := GenFileHash(buf) + filepath.Ext(inner_f.Name())
fmt.Println("Uploading .. " + filename)
err := bucket.Put(filename, buf, mime, s3.BucketOwnerFull, s3.Options{})
if err != nil {
log.Fatal(err)
}
}
wg.Done()
}(f)
}
wg.Wait()
}
func GetSignedURL(bucket *s3.Bucket) []SignedURLResponse {
ch := make(chan SignedURLResponse)
list, err := bucket.List("", "", "", 100)
if err != nil {
log.Fatal(err)
}
count := 0
for _, c := range list.Contents {
count++
go func(inner_c s3.Key) {
signed_url := bucket.SignedURL(inner_c.Key, time.Now().Add(time.Second*60))
ch <- SignedURLResponse{URL: signed_url}
}(c)
}
signed_urls := make([]SignedURLResponse, 0, count)
for i := 0; i < count; i++ {
signed_urls = append(signed_urls, <-ch)
}
return signed_urls
}
func main() {
auth, err := aws.EnvAuth()
if err != nil {
panic(err)
}
s3client := s3.New(auth, aws.APNortheast)
bucket := s3client.Bucket("test-bucket")
S3Upload(bucket, "images")
fmt.Println("Done")
// SignedURL の取得
signed_urls := GetSignedURL(bucket)
fmt.Println(signed_urls)
}
参考文献
以下の記事を参考にしました。ありがとうございました。