بارگذاری Pre-signed داخل صندوقچه
اگر بخواهید بدون انتشار کلیدهای احراز هویت خود، امکان بارگذاری آبجکت را در اختیار دیگران قرار دهید، در این شرایط میتوانید از روش بارگذاری pre-signed استفاده کنید.
مولفهها
- نام صندوقچه
- نام آبجکت
- سطح دسترسی صندوقچه
- مدت زمان اعتبار لینک (اختیاری)
نام آبجکت (Key)
نام آبجکت پس از بارگذاری داخل صندوقچه
- NET.
- PHP
- Python
- Javascript
- GO
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
namespace GenPresignedURLExample
{
using System;
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
/// <summary>
/// This example generates a presigned URL for an object in an Amazon
/// Simple Storage Service (Amazon S3) bucket. The generated example
/// remains valid for the specified number of hours. This example was
/// created using the AWS SDK for .NET version 3.7 and .NET Core 5.0.
/// </summary>
public class GenPresignedURL
{
private const string OBJECT_NAME = "<BUCKET_NAME>";
private static string LOCAL_PATH = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
public static void Main()
{
const string bucketName = "<OBJECT_NAME>";
var path = $"{LOCAL_PATH}/{OBJECT_NAME}";
var objectKey = path;
// Specify how long the presigned URL lasts, in hours
const double timeoutDuration = 12;
// Specify the AWS Region of your Amazon S3 bucket. An example AWS
// Region is shown.
RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
var awsCredentials = new Amazon.Runtime.BasicAWSCredentials("<ACCESS-KEY>", "<SECRET-KEY>");
var config = new AmazonS3Config { ServiceURL = "<ENDPOINT>" };
IAmazonS3 _s3Client = new AmazonS3Client(awsCredentials, config);
string urlString = GeneratePresignedURL(_s3Client, bucketName, objectKey, timeoutDuration);
Console.WriteLine($"The generated URL is: {urlString}");
}
/// <summary>
/// Gemerate a presigned URL that can be used to access the file named
/// in the ojbectKey parameter for the amount of time specified in the
/// duration parameter.
/// </summary>
/// <param name="client">An initialized S3 client object used to call
/// the GetPresignedUrl method.</param>
/// <param name="bucketName">The name of the S3 bucket containing the
/// object for which to create the presigned URL.</param>
/// <param name="objectKey">The name of the object to access with the
/// presigned URL.</param>
/// <param name="duration">The length of time for which the presigned
/// URL will be valid.</param>
/// <returns>A string representing the generated presigned URL.</returns>
public static string GeneratePresignedURL(IAmazonS3 client, string bucketName, string objectKey, double duration)
{
string urlString = string.Empty;
try
{
GetPreSignedUrlRequest request = new ()
{
BucketName = bucketName,
Key = objectKey,
Expires = DateTime.UtcNow.AddHours(duration),
};
urlString = client.GetPreSignedURL(request);
}
catch (AmazonS3Exception ex)
{
Console.WriteLine($"Error:'{ex.Message}'");
}
return urlString;
}
}
}
<?php
// https://docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTForms.html
require('client.php');
$bucket = $config['sample_bucket'];
// Set some defaults for form input fields
$formInputs = ['acl' => 'public-read'];
// Construct an array of conditions for policy
$options = [
['acl' => 'public-read'],
['bucket' => $bucket],
['starts-with', '$key', 'users/'],
];
// Optional: configure expiration time string
$expires = '+2 hours';
$postObject = new \Aws\S3\PostObjectV4(
$client,
$bucket,
$formInputs,
$options,
$expires
);
// Get attributes to set on an HTML form, e.g., action, method, enctype
$formAttributes = $postObject->getFormAttributes();
// Get form input fields. This will include anything set as a form input in
// the constructor, the provided JSON policy, your AWS access key ID, and an
// auth signature.
$formInputs = $postObject->getFormInputs();
var_dump($formInputs);
ابتدا با استفاده از کد زیر یک لینک امضا شده برای بارگذاری ایجاد کنید:
import json
import logging
import os
import pathlib
import boto3
import requests
from botocore.exceptions import ClientError
logging.basicConfig(level=logging.INFO)
config = {
"endpoint_url": "https://s3.ir-thr-at1.arvanstorage.ir",
"secret_key": "YOUR_SECRET_KEY",
"access_key": "YOUR_ACCESS_KEY"
}
# s3 client instance
s3_client = boto3.client(
's3',
endpoint_url=config['endpoint_url'],
aws_access_key_id=config['access_key'],
aws_secret_access_key=config['secret_key']
)
def create_presigned_post(bucket_name, object_name, fields=None, conditions=None, expiration=3600):
"""Generate a pre-signed URL S3 POST request to upload a file
:param bucket_name: string
:param object_name: string
:param fields: Dictionary of prefilled form fields
:param conditions: List of conditions to include in the policy
:param expiration: Time in seconds for the presigned URL to remain valid
:return: Dictionary with the following keys:
url: URL to post to
fields: Dictionary of form fields and values to submit with the POST
:return: None if error.
"""
# Generate a pre-signed S3 POST URL
try:
response = s3_client.generate_presigned_post(
bucket_name,
object_name,
Fields=fields,
Conditions=conditions,
ExpiresIn=expiration
)
except ClientError as e:
logging.error(e)
return None
# The response contains the presigned URL and required fields
return response
def main():
bucket_name = 'YOUR_BUCKET_NAME'
object_name = 'YOUR_OBJECT_NAME'
response = create_presigned_post(bucket_name, object_name)
logging.info(f"response: {response}")
خروجی مورد انتظار بهشکل زیر است:
INFO:root:response: {'url': 'https://s3.ir-thr-at1.arvanstorage.ir/YOUR_BUCKET_NAME', 'fields': {'key': 'YOUR_OBJECT_NAME', 'AWSAccessKeyId': 'xxxxx-xxxxx-xxxxx-xxxx-xxxxxxx', 'policy': 'xxxxxxxxxx', 'signature': 'xxxxxxxxx-xxxxxxx-xxx'}}
سپس باید تنظیمات CORS را برای متد POST روی صندوقچه فعال کنید. برای این کار میتوانید از تکه کد زیر استفاده کنید:
def set_bucket_cors(bucket: str) -> None:
"""
Set CORS configuration for the specified bucket
:param bucket: bucket's name
:return:
"""
# Define the configuration rules
cors_configuration = {
'CORSRules': [{
'AllowedHeaders': ['*'],
'AllowedMethods': ['POST'],
'AllowedOrigins': ['*']
}]
}
s3_client.put_bucket_cors(
Bucket=bucket,
CORSConfiguration=cors_configuration
)
توجه داشته باشید که میتوانید تنظیمات AllowedOrigins را با توجه به دامنهی سایت خود تغییر دهید.
در آخر با استفاده از اطلاعات امضا شده، بهشکل زیر فایلهای خود را بارگذاری کنید:
<html>
<script>
function onClick(){
var fileVal=document.getElementById("file_to_upload").files[0];
console.log(fileVal)
uploadFile(fileVal)
}
function uploadFile(file) {
var formData = new FormData();
formData.append("key", "YOUR_OBJECT_NAME");
formData.append("AWSAccessKeyId", "************************");
formData.append("policy", "************************");
formData.append("signature", "***********************");
formData.append("file", file);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function (e) {
if (e.lengthComputable) {
console.log(e.loaded / e.total);
}
});
xhr.upload.addEventListener("load", function () {
console.log("uploaded");
});
xhr.open("POST", "https://s3.ir-thr-at1.arvanstorage.ir/YOUR_BUCKET_NAME");
xhr.send(formData);
}
</script>
<body>
<input id="file_to_upload" type="file" name="file" /> <br />
<input type="button" onclick="onClick()" name="submit" value="Upload to Arvan S3" />
</body>
</html>
// Import required AWS SDK clients and commands for Node.js
const { S3Client } = require('@aws-sdk/client-s3');
const { createPresignedPost } = require('@aws-sdk/s3-presigned-post');
const { createReadStream } = require('fs');
const FormData = require('form-data');
// Create an S3 client service object
const s3 = new S3Client({
region: 'default',
endpoint: 'endpoint_url',
forcePathStyle: false,
credentials: {
accessKeyId: 'access_key',
secretAccessKey: 'secret_key',
},
});
const BUCKET_NAME = 'sample_bucket';
const file = __dirname + '/../files/file.png';
const Conditions = [
{ acl: 'public-read' },
{ bucket: BUCKET_NAME },
['starts-with', '$key', 'user/'],
];
const Bucket = BUCKET_NAME;
const Key = 'user/file1.png';
const Fields = {
acl: 'public-read',
};
const run = async () => {
const { url, fields } = await createPresignedPost(s3, {
Bucket,
Key,
Conditions,
Fields,
Expires: 600, //Seconds before the presigned post expires. 3600 by default.
});
const form = new FormData();
Object.entries(fields).forEach(([field, value]) => {
form.append(field, value);
});
form.append('file', createReadStream(file));
form.submit(url, (err, res) => {
console.log(res.statusCode);
//handle the response
});
};
run();
package main
import (
"crypto/md5"
"encoding/base64"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Creates a 15 min URL to put a file that is exactly like Body
// that defined in PutObjectRequest
//
// Usage:
// go run upload_presigned.go BUCKET FILENAME
func main() {
if len(os.Args) != 3 {
exitErrorf("bucket and file name required\nUsage: %s bucket_name filename",
os.Args[0])
}
bucket := os.Args[1]
filename := os.Args[2]
fileContent, err := os.ReadFile(filename)
if err != nil {
exitErrorf("Unable to open file %q, %v", err)
}
h := md5.New()
content := strings.NewReader(string(fileContent))
content.WriteTo(h)
// Initialize a session in us-west-2 that the SDK will use to load
// credentials from the shared credentials file ~/.aws/credentials.
sess, err := session.NewSession(&aws.Config{
Credentials: credentials.NewStaticCredentials("<ACCESS_KEY>", "<SECRET_KEY>", ""),
})
svc := s3.New(sess, &aws.Config{
Region: aws.String("default"),
Endpoint: aws.String("<ENDPOINT_URL>"),
})
resp, _ := svc.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(filename),
Body: strings.NewReader(string(fileContent)),
})
md5s := base64.StdEncoding.EncodeToString(h.Sum(nil))
resp.HTTPRequest.Header.Set("Content-MD5", md5s)
url, err := resp.Presign(15 * time.Minute)
if err != nil {
fmt.Println("error presigning request", err)
return
}
fmt.Println(url)
fmt.Println()
req, err := http.NewRequest("PUT", url, strings.NewReader(string(fileContent)))
req.Header.Set("Content-MD5", md5s)
if err != nil {
fmt.Println("error creating request", url)
return
}
defClient, err := http.DefaultClient.Do(req)
fmt.Println(defClient, err)
}
func exitErrorf(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(1)
}
برای اجرای قطعه کد بالا با فرض نامگذاری فایل کد به upload_presigned.go میتوان از دستور زیر استفاده کرد:
go run upload_presigned.go BUCKET FILENAME
اگر مقدار Body در تابع PutObjectRequest تعریف نشده باشد و نیز مقدار Hash به Header این تابع اضافه نشده باشد کاربر میتواند با این URL آبجکت با هر مقداری را بارگذاری کند.