Jika Anda tidak membatasi jenis dan ukuran file yang dapat diunggah ke bucket Object Storage Service (OSS), bucket tersebut mungkin berisi objek besar atau objek jahat yang diunggah oleh pengguna. Hal ini dapat menyebabkan penggunaan penyimpanan dan konsumsi bandwidth yang tidak terduga, serta pemblokiran domain bucket dalam beberapa kasus. OSS tidak memiliki fitur terpisah untuk secara langsung membatasi jenis file dan ukuran dalam unggahan. Namun, Anda dapat menentukan batasan pada jenis file dan ukuran saat menghasilkan tanda tangan di server atau menulis logika pembatasan di sisi klien.
Hasilkan tanda tangan dan kebijakan untuk permintaan POST di sisi server
Dalam skenario di mana Anda ingin membatasi atribut objek yang akan diunggah, Anda perlu mendapatkan informasi yang diperlukan untuk memanggil operasi PostObject dari server aplikasi. Informasi tersebut mencakup tanda tangan dan kebijakan POST. Kemudian, klien dapat menggunakan informasi yang diperoleh untuk mengunggah objek langsung ke OSS tanpa menggunakan SDK OSS. Anda dapat menggunakan kebijakan yang dihasilkan oleh server aplikasi untuk membatasi atribut objek seperti ukuran dan jenisnya. Solusi ini cocok untuk skenario di mana Anda ingin mengunggah objek menggunakan formulir HTML. Solusi ini tidak mendukung unggahan multipart atau unggahan yang dapat dilanjutkan. Untuk informasi lebih lanjut, lihat PostObject.
Contoh kode
Contoh Kode Sisi Server
Berikut adalah contoh kode yang menunjukkan cara server aplikasi menghasilkan tanda tangan dan kebijakan POST untuk PostObject:
Contoh kode dapat diterapkan di Function Compute. oss-upload-post-signature-app
Python
import os
from hashlib import sha1 as sha
import json
import base64
import hmac
import datetime
import time
# Dapatkan AccessKey ID dari variabel lingkungan OSS_ACCESS_KEY_ID.
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
# Dapatkan Rahasia AccessKey dari variabel lingkungan OSS_ACCESS_KEY_SECRET.
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
# Ganti <YOUR_BUCKET> dengan nama bucket.
bucket = '<YOUR_BUCKET>'
# Setel host ke nilai dalam format BucketName.Endpoint. Ganti <YOUR_BUCKET> dengan nama bucket. Ganti <YOUR_ENDPOINT> dengan endpoint wilayah tempat bucket berada, seperti oss-cn-hangzhou.aliyuncs.com.
host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
# Tentukan awalan dalam nama objek yang ingin Anda unggah ke OSS.
upload_dir = 'user-dir-prefix/'
# Tentukan periode validitas. Unit: detik.
expire_time = 3600
def generate_expiration(seconds):
"""
Waktu kedaluwarsa dihitung berdasarkan periode validitas yang ditentukan. Unit: detik.
:param seconds: periode validitas (detik).
:return: string waktu dalam standar ISO 8601. Contoh: 2014-12-01T12:00:00.000Z.
"""
now = int(time.time())
expiration_time = now + seconds
gmt = datetime.datetime.utcfromtimestamp(expiration_time).isoformat()
gmt += 'Z'
return gmt
def generate_signature(access_key_secret, expiration, conditions, policy_extra_props=None):
"""
Hasilkan string tanda tangan.
:param access_key_secret: Rahasia AccessKey yang memiliki izin untuk mengakses bucket.
:param expiration: waktu ketika tanda tangan kedaluwarsa. Tentukan waktu dalam standar ISO 8601 dalam format yyyy-MM-ddTHH:mm:ssZ. Contoh: 2014-12-01T12:00:00.000Z.
:param conditions: kondisi kebijakan yang dapat digunakan untuk membatasi nilai yang dapat Anda tentukan selama unggahan formulir.
:param policy_extra_props: parameter kebijakan tambahan. Anda dapat melewatkan parameter tambahan sebagai dict.
:return: string tanda tangan.
"""
policy_dict = {
'expiration': expiration,
'conditions': conditions
}
if policy_extra_props is not None:
policy_dict.update(policy_extra_props)
policy = json.dumps(policy_dict).strip()
policy_encode = base64.b64encode(policy.encode())
h = hmac.new(access_key_secret.encode(), policy_encode, sha)
sign_result = base64.b64encode(h.digest()).strip()
return sign_result.decode()
def generate_upload_params():
policy = {
# Tentukan periode validitas.
"expiration": generate_expiration(expire_time),
# Tentukan kondisi kebijakan.
"conditions": [
# Jika success_action_redirect tidak ditentukan, kode status HTTP 204 dikembalikan setelah objek diunggah.
["eq", "$success_action_status", "200"],
# Nilai bidang formulir harus dimulai dengan awalan yang ditentukan. Misalnya, jika nilai bidang kunci dimulai dengan user/user1, kondisinya adalah ["starts-with", "$key", "user/user1"].
["starts-with", "$key", upload_dir],
# Tentukan ukuran minimum dan maksimum objek yang dapat diunggah. Unit: byte.
["content-length-range", 1, 1000000],
# Tentukan jenis file yang diizinkan.
["in", "$content-type", ["image/jpg", "image/png"]]
]
}
signature = generate_signature(access_key_secret, policy.get('expiration'), policy.get('conditions'))
response = {
'policy': base64.b64encode(json.dumps(policy).encode('utf-8')).decode(),
'ossAccessKeyId': access_key_id,
'signature': signature,
'host': host,
'dir': upload_dir
# Tentukan parameter tambahan.
}
return json.dumps(response)
Java
import com.aliyun.help.demo.uploading_to_oss_directly_postsignature.config.OssConfig;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.codehaus.jettison.json.JSONObject;
import java.util.Date;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import javax.annotation.PreDestroy;
@Controller
public class PostSignatureController {
@Autowired
private OSS ossClient;
@Autowired
private OssConfig ossConfig;
@GetMapping("/get_post_signature_for_oss_upload")
@ResponseBody
public String generatePostSignature() {
JSONObject response = new JSONObject();
try {
long expireEndTime = System.currentTimeMillis() + ossConfig.getExpireTime() * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, ossConfig.getDir());
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
response.put("ossAccessKeyId", ossConfig.getAccessKeyId());
response.put("policy", encodedPolicy);
response.put("signature", postSignature);
response.put("dir", ossConfig.getDir());
response.put("host", ossConfig.getHost());
} catch (
OSSException oe) {
System.out.println("Menangkap OSSException, yang berarti permintaan Anda sampai ke OSS, "
+ "tetapi ditolak dengan respons kesalahan karena alasan tertentu.");
// Asumsikan metode ini ada.
System.out.println("Kode Status HTTP: " + oe.getRawResponseError());
System.out.println("Pesan Kesalahan: " + oe.getErrorMessage());
System.out.println("Kode Kesalahan: " + oe.getErrorCode());
System.out.println("ID Permintaan: " + oe.getRequestId());
System.out.println("ID Host: " + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Menangkap ClientException, yang berarti klien mengalami "
+ "masalah internal serius saat mencoba berkomunikasi dengan OSS, "
+ "seperti tidak dapat mengakses jaringan.");
System.out.println("Pesan Kesalahan: " + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
return response.toString();
}
}
}
@Configuration
public class OssConfig {
/**
* Ganti <YOUR-ENDPOINT> dengan endpoint wilayah tempat bucket berada, seperti oss-cn-hangzhou.aliyuncs.com.
*/
private String endpoint = "<YOUR-ENDPOINT>";
/**
* Ganti <YOUR-BUCKET> dengan nama bucket.
*/
private String bucket = "<YOUR-BUCKET>";
/**
* Tentukan awalan dalam nama objek di OSS.
*/
private String dir = "user-dir-prefix/";
/**
* Tentukan periode validitas. Unit: detik.
*/
private long expireTime = 3600;
/**
* Buat host.
*/
private String host = "http://" + bucket + "." + endpoint;
/**
* Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
*/
private String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
/**
* Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
*/
private String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
private OSS ossClient;
@Bean
public OSS getOssClient() {
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
return ossClient;
}
@Bean
public String getHost() {
return host;
}
@Bean
public String getAccessKeyId() {
return accessKeyId;
}
@Bean
public long getExpireTime() {
return expireTime;
}
@Bean
public String getDir() {
return dir;
}
@PreDestroy
public void onDestroy() {
ossClient.shutdown();
}
}
Go
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
var (
// Dapatkan ID AccessKey dari variabel lingkungan OSS_ACCESS_KEY_ID.
accessKeyId = os.Getenv("OSS_ACCESS_KEY_ID")
// Dapatkan Rahasia AccessKey dari variabel lingkungan OSS_ACCESS_KEY_SECRET.
accessKeySecret = os.Getenv("OSS_ACCESS_KEY_SECRET")
// Tentukan host. Format: BucketName.Endpoint. Ganti ${your-bucket} dengan nama bucket. Ganti ${your-endpoint} dengan endpoint OSS, seperti oss-cn-hangzhou.aliyuncs.com.
host = "http://${your-bucket}.${your-endpoint}"
// Tentukan awalan dalam nama objek yang ingin Anda unggah ke OSS.
uploadDir = "user-dir-prefix/"
// Tentukan periode validitas. Unit: detik.
expireTime = int64(3600)
)
type ConfigStruct struct {
Expiration string `json:"expiration"`
Conditions [][]interface{} `json:"conditions"`
}
type PolicyToken struct {
AccessKeyId string `json:"ossAccessKeyId"`
Host string `json:"host"`
Signature string `json:"signature"`
Policy string `json:"policy"`
Directory string `json:"dir"`
}
func getGMTISO8601(expireEnd int64) string {
return time.Unix(expireEnd, 0).UTC().Format("2006-01-02T15:04:05Z")
}
func getPolicyToken() string {
now := time.Now().Unix()
expireEnd := now + expireTime
tokenExpire := getGMTISO8601(expireEnd)
var config ConfigStruct
config.Expiration = tokenExpire
var condition []string
condition = append(condition, "starts-with")
condition = append(condition, "$key")
condition = append(condition, uploadDir)
config.Conditions = append(config.Conditions, condition)
result, err := json.Marshal(config)
if err != nil {
fmt.Println("callback json err:", err)
return ""
}
encodedResult := base64.StdEncoding.EncodeToString(result)
h := hmac.New(sha1.New, []byte(accessKeySecret))
io.WriteString(h, encodedResult)
signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
policyToken := PolicyToken{
AccessKeyId: accessKeyId,
Host: host,
Signature: signedStr,
Policy: encodedResult,
Directory: uploadDir,
}
response, err := json.Marshal(policyToken)
if err != nil {
fmt.Println("json err:", err)
return ""
}
return string(response)
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "templates/index.html")
return
} else if r.URL.Path == "/get_post_signature_for_oss_upload" {
policyToken := getPolicyToken()
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(policyToken))
return
}
http.NotFound(w, r)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
PHP
<?php
function gmt_iso8601($time)
{
return str_replace('+00:00', '.000Z', gmdate('c', $time));
}
// Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID dan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah dikonfigurasi.
$accessKeyId = getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
$accessKeySecret = getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Tentukan host. Format: <YOUR-BUCKET>.<YOUR-ENDPOINT>.
$host = 'http://<YOUR-BUCKET>.<YOUR-ENDPOINT>';
// Tentukan awalan dalam nama objek yang ingin Anda unggah.
$dir = 'user-dir-prefix/';
$now = time();
// Tentukan waktu kedaluwarsa kebijakan. Jika waktu kedaluwarsa berakhir, akses akan ditolak. Dalam contoh ini, waktu kedaluwarsa diatur menjadi 10 detik.
$expire = 30;
$end = $now + $expire;
$expiration = gmt_iso8601($end);
// Tentukan ukuran maksimum objek yang dapat diunggah.
$condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
$conditions[] = $condition;
// Tentukan objek yang dapat diunggah. Dalam contoh ini, hanya objek yang namanya dimulai dengan nilai parameter $dir yang dapat diunggah. Ini adalah pengaturan opsional yang mencegah objek diunggah ke direktori berbeda di bucket menggunakan kebijakan.
$start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
$conditions[] = $start;
$arr = array('expiration' => $expiration, 'conditions' => $conditions);
$policy = json_encode($arr);
$base64_policy = base64_encode($policy);
$string_to_sign = $base64_policy;
$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $accessKeySecret, true));
$response = array();
$response['ossAccessKeyId'] = $accessKeyId;
$response['host'] = $host;
$response['policy'] = $base64_policy;
$response['signature'] = $signature;
$response['dir'] = $dir;
echo json_encode($response);
Node.js
const express = require("express");
const { Buffer } = require("buffer");
const OSS = require("ali-oss");
const app = express();
const path = require("path");
const config = {
// Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
// Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
// Ganti <YOUR-BUCKET> dengan nama bucket.
bucket: "<YOUR-BUCKET>",
// Tentukan awalan dalam nama objek yang ingin Anda unggah ke OSS.
dir: "prefix/",
};
app.use(express.static(path.join(__dirname, "templates")));
app.get("/get_post_signature_for_oss_upload", async (req, res) => {
const client = new OSS(config);
const date = new Date();
// Tentukan periode validitas tanda tangan. Unit: detik.
date.setSeconds(date.getSeconds() + 3600);
const policy = {
expiration: date.toISOString(),
conditions: [
// Tentukan batas ukuran objek yang dapat diunggah.
["content-length-range", 0, 1048576000],
// Tentukan bucket ke mana objek dapat diunggah.
{ bucket: client.options.bucket },
],
};
const formData = await client.calculatePostSignature(policy);
const host = `http://${config.bucket}.${
(await client.getBucketLocation()).location
}.aliyuncs.com`.toString();
const params = {
policy: formData.policy,
signature: formData.Signature,
ossAccessKeyId: formData.OSSAccessKeyId,
host,
dir: config.dir,
};
res.json(params);
});
app.get(/^(.+)*\.(html|js)$/i, async (req, res) => {
res.sendFile(path.join(__dirname, "./templates", req.originalUrl));
});
app.listen(8000, () => {
console.log("http://127.0.0.1:8000");
});
Ruby
require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
# Setel jalur folder publik ke subfolder templates dalam folder saat ini.
set :public_folder, File.dirname(__FILE__) + '/templates'
# Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
$access_key_id = ENV['ALIBABA_CLOUD_ACCESS_ID']
# Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
$access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_SECRET']
# Tentukan host. Host dalam format <bucketname>.<endpoint>.
$host = 'http://<bucketname>.<endpoint>';
# Tentukan awalan dalam nama objek yang ingin Anda unggah.
$upload_dir = 'user-dir-prefix/'
# Tentukan periode validitas. Unit: detik.
$expire_time = 30
$server_ip = "0.0.0.0"
$server_port = 8000
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
puts "App server berjalan pada: http://#{$server_ip}:#{$server_port}"
def hash_to_jason(source_hash)
jason_string = source_hash.to_json;
jason_string.gsub!("\":[", "\": [")
jason_string.gsub!("\",\"", "\", \"")
jason_string.gsub!("],\"", "], \"")
jason_string.gsub!("\":\"", "\": \"")
jason_string
end
def get_token()
expire_syncpoint = Time.now.to_i + $expire_time
expire = Time.at(expire_syncpoint).utc.iso8601()
response.headers['expire'] = expire
policy_dict = {}
condition_arrary = Array.new
array_item = Array.new
array_item.push('starts-with')
array_item.push('$key')
array_item.push($upload_dir)
condition_arrary.push(array_item)
policy_dict["conditions"] = condition_arrary
policy_dict["expiration"] = expire
policy = hash_to_jason(policy_dict)
policy_encode = Base64.strict_encode64(policy).chomp;
h = OpenSSL::HMAC.digest('sha1', $access_key_secret, policy_encode)
hs = Digest::MD5.hexdigest(h)
sign_result = Base64.strict_encode64(h).strip()
token_dict = {}
token_dict['ossAccessKeyId'] = $access_key_id
token_dict['host'] = $host
token_dict['policy'] = policy_encode
token_dict['signature'] = sign_result
token_dict['expire'] = expire_syncpoint
token_dict['dir'] = $upload_dir
result = hash_to_jason(token_dict)
result
end
set :bind, $server_ip
set :port, $server_port
get '/get_post_signature_for_oss_upload' do
token = get_token()
puts "Token: #{token}"
token
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
end
end
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
$server_ip = "0.0.0.0"
$server_port = 8000
puts "App server berjalan pada: http://#{$server_ip}:#{$server_port}"
set :bind, $server_ip
set :port, $server_port
get '/get_sts_token_for_oss_upload' do
token = get_sts_token_for_oss_upload()
response = {
"AccessKeyId" => token["Credentials"]["AccessKeyId"],
"AccessKeySecret" => token["Credentials"]["AccessKeySecret"],
"SecurityToken" => token["Credentials"]["SecurityToken"]
}
response.to_json
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
end
C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.Collections.Generic;
using System;
using System.Globalization;
using System.Text;
using System.Security.Cryptography;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace YourNamespace
{
public class Program
{
private ILogger<Program> _logger;
// Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
// Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Tentukan host. Format: BucketName.Endpoint. Ganti <YOUR-BUCKET> dengan nama bucket. Ganti <YOUR-ENDPOINT> dengan endpoint wilayah tempat bucket berada, seperti oss-cn-hangzhou.aliyuncs.com.
public string Host { get; set; } = "<YOUR-BUCKET>.<YOUR-ENDPOINT>";
// Tentukan awalan dalam nama objek yang ingin Anda unggah ke OSS.
public string UploadDir { get; set; } = "user-dir-prefix/";
// Tentukan periode validitas. Unit: detik.
public int ExpireTime { get; set; } = 3600;
public class PolicyConfig
{
public string expiration { get; set; }
public List<List<object>> conditions { get; set; }
}
public class PolicyToken
{
public string Accessid { get; set; }
public string Policy { get; set; }
public string Signature { get; set; }
public string Dir { get; set; }
public string Host { get; set; }
public string Expire { get; set; }
}
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
builder.Logging.AddConsole();
var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
app.UseStaticFiles();
app.MapGet("/", async (context) =>
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
var htmlContent = await File.ReadAllTextAsync(filePath);
await context.Response.WriteAsync(htmlContent);
logger.LogInformation("GET request ke root path");
});
app.MapGet("/get_post_signature_for_oss_upload", async (context) =>
{
var program = new Program(logger);
var token = program.GetPolicyToken();
logger.LogInformation($"Token: {token}");
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(token);
});
app.Run();
}
public Program(ILogger<Program> logger)
{
_logger = logger;
}
private string ToUnixTime(DateTime dateTime)
{
return ((DateTimeOffset)dateTime).ToUnixTimeSeconds().ToString();
}
private string GetPolicyToken()
{
var expireDateTime = DateTime.Now.AddSeconds(ExpireTime);
var config = new PolicyConfig
{
expiration = FormatIso8601Date(expireDateTime),
conditions = new List<List<object>>()
};
config.conditions.Add(new List<object>
{
"content-length-range", 0, 1048576000
});
var policy = JsonConvert.SerializeObject(config);
var policyBase64 = EncodeBase64("utf-8", policy);
var signature = ComputeSignature(AccessKeySecret, policyBase64);
var policyToken = new PolicyToken
{
Accessid = AccessKeyId,
Host = Host,
Policy = policyBase64,
Signature = signature,
Expire = ToUnixTime(expireDateTime),
Dir = UploadDir
};
return JsonConvert.SerializeObject(policyToken);
}
private string FormatIso8601Date(DateTime dtime)
{
return dtime.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'",
CultureInfo.CurrentCulture);
}
private string EncodeBase64(string codeType, string code)
{
string encode = "";
byte[] bytes = Encoding.GetEncoding(codeType).GetBytes(code);
try
{
encode = Convert.ToBase64String(bytes);
}
catch
{
encode = code;
}
return encode;
}
private string ComputeSignature(string key, string data)
{
using (var algorithm = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
{
return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(data)));
}
}
}
}
Hasilkan URL bertanda tangan di sisi server
Bidang content-length-range tidak didukung untuk penandatanganan URL. Oleh karena itu, Anda tidak dapat menggunakan metode ini untuk membatasi ukuran file yang akan diunggah. Jika Anda ingin membatasi unggahan ke jenis file tertentu, Anda dapat menentukan header Content-Type saat mengonfigurasi server untuk menghasilkan URL bertanda tangan. Saat klien menggunakan URL bertanda tangan untuk mengunggah file, file tersebut harus dalam salah satu format yang ditentukan. Untuk informasi lebih lanjut, lihat Tambahkan Tanda Tangan ke URL.
Contoh kode
Contoh Kode Sisi Server
Berikut adalah contoh kode yang menunjukkan cara mendapatkan URL bertanda tangan dari server aplikasi:
Contoh kode dapat diterapkan di Function Compute. oss-upload-presigned-url-app
Python
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan bahwa variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# Ganti <YOUR_ENDPOINT> dengan endpoint wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur endpoint ke https://oss-cn-hangzhou.aliyuncs.com.
# Ganti <YOUR_BUCKET> dengan nama bucket.
bucket = oss2.Bucket(auth, '<YOUR_ENDPOINT>', '<YOUR_BUCKET>')
# Tentukan periode validitas. Unit: detik.
expire_time = 3600
# Tentukan jalur lengkap objek. Contoh: exampledir/exampleobject.png. Jangan sertakan nama bucket dalam jalur lengkap.
object_name = 'exampledir/exampleobject.png'
def generate_presigned_url():
# Tentukan header.
headers = dict()
# Tentukan header Content-Type.
headers['Content-Type'] = 'image/png'
# Tentukan kelas penyimpanan.
# headers["x-oss-storage-class"] = "Standard"
# Secara default, OSS mengidentifikasi garis miring (/) dalam jalur lengkap objek sebagai karakter escape saat URL bertanda tangan dihasilkan. Oleh karena itu, Anda tidak dapat menggunakan URL bertanda tangan secara langsung.
# Atur parameter slash_safe ke True. Dengan cara ini, OSS tidak mengidentifikasi garis miring (/) dalam jalur lengkap objek sebagai karakter escape. Dalam hal ini, Anda dapat menggunakan URL bertanda tangan yang dihasilkan untuk mengunggah objek.
url = bucket.sign_url('PUT', object_name, expire_time, slash_safe=True, headers=headers)
return url
Java
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Bean;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.net.URL;
import java.util.Date;
import javax.annotation.PreDestroy;
@Configuration
public class OssConfig {
/**
* Ganti <your-endpoint> dengan endpoint wilayah tempat bucket berada, seperti oss-cn-hangzhou.aliyuncs.com.
*/
private static final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
/**
* Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
*/
@Value("${ALIBABA_CLOUD_ACCESS_KEY_ID}")
private String accessKeyId;
/**
* Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
*/
@Value("${ALIBABA_CLOUD_ACCESS_KEY_SECRET}")
private String accessKeySecret;
private OSS ossClient;
@Bean
public OSS getSssClient() {
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
return ossClient;
}
@PreDestroy
public void onDestroy() {
ossClient.shutdown();
}
}
@Controller
public class PresignedURLController {
/**
* Ganti <your-bucket> dengan nama bucket.
* Tentukan awalan dalam nama objek yang ingin Anda unggah ke OSS.
* Ganti <your-object> dengan jalur lengkap objek. Contoh: exampleobject.txt. Jangan sertakan nama bucket dalam jalur lengkap.
* Tentukan waktu kedaluwarsa. Unit: milidetik.
*/
private static final String BUCKET_NAME = "<your-bucket>";
private static final String OBJECT_NAME = "<your-object>";
private static final long EXPIRE_TIME = 3600 * 1000L;
@Autowired
private OSS ossClient;
@GetMapping("/get_presigned_url_for_oss_upload")
@ResponseBody
public String generatePresignedURL() {
try {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BUCKET_NAME, OBJECT_NAME, HttpMethod.PUT);
Date expiration = new Date(System.currentTimeMillis() + EXPIRE_TIME);
request.setExpiration(expiration);
request.setContentType("image/png");
URL signedUrl = ossClient.generatePresignedUrl(request);
return signedUrl.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}Go
package main
import (
"fmt"
"net/http"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func getURL() string {
// Tentukan endpoint wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur endpoint ke https://oss-cn-hangzhou.aliyuncs.com. Tentukan endpoint aktual Anda.
endpoint := "https://oss-cn-beijing.aliyuncs.com"
// Tentukan nama bucket. Contoh: examplebucket.
bucketName := "examplebucket"
// Tentukan jalur lengkap objek. Contoh: exampledir/exampleobject.txt. Jangan sertakan nama bucket dalam jalur lengkap.
objectName := "exampledir/exampleobject.txt"
// Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan bahwa variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID dan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah dikonfigurasi.
accessKeyID := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
accessKeySecret := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
if err != nil {
fmt.Println("json err:", err)
}
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("json err:", err)
}
options := []oss.Option{
oss.ContentType("image/png"),
}
signedURL, err := bucket.SignURL(objectName, oss.HTTPPut, 60, options...)
if err != nil {
fmt.Println("json err:", err)
}
return signedURL
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "templates/index.html")
return
} else if r.URL.Path == "/get_presigned_url_for_oss_upload" {
url := getURL()
fmt.Fprintf(w, "%s", url)
return
}
http.NotFound(w, r)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
PHP
<?php
require_once __DIR__ . '/vendor/autoload.php';
use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Http\RequestCore;
use OSS\Http\ResponseCore;
// Sebelum menjalankan kode contoh, pastikan bahwa variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID dan ALIBABA_CLOUD_ACCESS_KEY_SECRET telah dikonfigurasi.
$accessKeyId = getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
$accessKeySecret = getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Tentukan endpoint wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur endpoint ke https://oss-cn-hangzhou.aliyuncs.com.
$endpoint = "<YOUR-ENDPOINT>";
// Tentukan nama bucket.
$bucket= "<YOUR-BUCKET>";
// Tentukan jalur lengkap objek. Jangan sertakan nama bucket dalam jalur lengkap.
$object = "test.png";
// Atur periode validitas URL bertanda tangan menjadi 3.600 detik.
$timeout = 3600;
try {
$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false);
// Hasilkan URL bertanda tangan.
$signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT", array('Content-Type' => 'image/png'));
// Tampilkan data yang dikembalikan.
echo $signedUrl;
} catch (OssException $e) {
printf($e->getMessage() . "\n");
return;
}
Node.js
const express = require("express");
const { Buffer } = require("buffer");
const OSS = require("ali-oss");
const app = express();
const path = require("path");
const fs = require("fs");
const axios = require("axios");
const config = {
// Tentukan wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur wilayah ke oss-cn-hangzhou.
region: '<YOURREGION>',
// Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
// Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
// Ganti <YOUR-BUCKET> dengan nama bucket.
bucket: "<YOUR-BUCKET>",
}
const object = "examplefile.png";
app.use(express.static(path.join(__dirname, "templates")));
app.get("/get_presigned_url_for_oss_upload", async (req, res) => {
const client = new OSS(config);
const url = client.signatureUrl(object, {
method: "PUT",
"Content-Type": "application/x-www-form-urlencoded",
});
res.send(url);
console.log(url);
});
app.listen(8000, () => {
console.log("http://127.0.0.1:8000");
});
Ruby
require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
require 'aliyun/oss'
include Aliyun::OSS
# Setel jalur folder publik ke subfolder templates dalam folder saat ini.
set :public_folder, File.dirname(__FILE__) + '/templates'
# Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
$access_key_id = ENV['ALIBABA_CLOUD_ACCESS_KEY_ID']
# Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_SECRET.
$access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
# Tentukan jalur lengkap objek. Contoh: exampledir/exampleobject.png. Jangan sertakan nama bucket dalam jalur lengkap.
object_key = 'exampledir/exampleobject.png'
def get_presigned_url(client, object_key)
# Ganti <YOUR-BUCKET> dengan nama bucket.
bucket = client.get_bucket('<YOUR-BUCKET>')
# Hasilkan URL bertanda tangan dan atur periode validitas URL menjadi 3600. Unit: detik.
bucket.object_url(object_key, 3600)
end
client = Aliyun::OSS::Client.new(
# Tentukan endpoint wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur endpoint ke https://oss-cn-hangzhou.aliyuncs.com.
endpoint: '<YOUR-ENDPOINT>',
# Dapatkan kredensial akses dari variabel lingkungan. Sebelum menjalankan kode contoh, pastikan bahwa variabel lingkungan OSS_ACCESS_KEY_ID dan OSS_ACCESS_KEY_SECRET telah dikonfigurasi.
access_key_id: $access_key_id,
access_key_secret: $access_key_secret
)
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
$server_ip = "0.0.0.0"
$server_port = 8000
puts "App server berjalan pada: http://#{$server_ip}:#{$server_port}"
set :bind, $server_ip
set :port, $server_port
get '/get_presigned_url_for_oss_upload' do
url = get_presigned_url(client, object_key.to_s)
puts "Token: #{url}"
url
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
end
C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System.IO;
using System;
using Microsoft.Extensions.Logging;
using Aliyun.OSS;
namespace YourNamespace
{
public class Program
{
private ILogger<Program> _logger;
// Dapatkan ID AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_ID.
public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
// Dapatkan Rahasia AccessKey dari variabel lingkungan ALIBABA_CLOUD_ACCESS_KEY_SECRET.
public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Ganti <YOUR-ENDPOINT> dengan endpoint wilayah tempat bucket berada. Misalnya, jika bucket berada di wilayah China (Hangzhou), atur endpoint ke https://oss-cn-hangzhou.aliyuncs.com.
private string EndPoint { get; set; } = "<YOUR-ENDPOINT>";
// Ganti <YOUR-BUCKET> dengan nama bucket.
private string BucketName { get; set; } = "<YOUR-BUCKET>";
private string ObjectName { get; set; } = "exampledir/exampleobject2.png";
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Tentukan logging.
builder.Logging.AddConsole();
var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
app.UseStaticFiles(); // Tambahkan baris ini untuk mengaktifkan middleware file statis
app.MapGet("/", async (context) =>
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
var htmlContent = await File.ReadAllTextAsync(filePath);
await context.Response.WriteAsync(htmlContent);
// Tampilkan log.
logger.LogInformation("GET request ke root path");
});
app.MapGet("/get_presigned_url_for_oss_upload", async (context) =>
{
var program = new Program(logger);
var signedUrl = program.GetSignedUrl();
logger.LogInformation($"SignedUrl: {signedUrl}"); // Tampilkan nilai token.
await context.Response.WriteAsync(signedUrl);
});
app.Run();
}
// Injeksi ILogger.
public Program(ILogger<Program> logger)
{
_logger = logger;
}
private string GetSignedUrl()
{
// Buat instance OSSClient.
var ossClient = new OssClient(EndPoint, AccessKeyId, AccessKeySecret);
// Buat permintaan untuk menghasilkan URL bertanda tangan.
var generatePresignedUriRequest = new GeneratePresignedUriRequest(BucketName, ObjectName, SignHttpMethod.Put)
{
Expiration = DateTime.Now.AddHours(1),
ContentType = "image/png"
};
var signedUrl = ossClient.GeneratePresignedUri(generatePresignedUriRequest);
return signedUrl.ToString();
}
}
}
Implementasi pembatasan sisi klien
Anda dapat menggunakan kode JavaScript di sisi klien untuk mengizinkan unggahan file yang memenuhi persyaratan atribut tertentu. Untuk membatasi unggahan ke jenis file dan ukuran tertentu, gunakan pernyataan kondisional untuk memeriksa apakah file yang akan diunggah memenuhi persyaratan yang ditentukan. Jika ya, unggahan diizinkan; jika tidak, unggahan ditolak dan peringatan atau pesan kesalahan dikembalikan. Harap diperhatikan bahwa implementasi pembatasan sisi klien tidak berlaku untuk unggahan yang menggunakan kredensial akses sementara yang disediakan oleh Security Token Service (STS). Jika kredensial akses sementara bocor, pengguna jahat mungkin dapat melewati pembatasan sisi klien dan mengunggah konten jahat ke bucket OSS Anda.
Contoh kode
Pembatasan Sisi Klien
Berikut adalah contoh kode yang menggunakan atribut files dan atribut accept dalam elemen <input type="file"> untuk memeriksa apakah ukuran file dan jenis file memenuhi persyaratan:
<!DOCTYPE html>
<html>
<head>
<title>Unggah file</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<input type="file" id="file-upload" accept="image/jpeg, image/png, application/pdf" />
<button onclick="uploadFile()">Unggah</button>
<script>
function uploadFile() {
const fileInput = document.getElementById('file-upload');
const file = fileInput.files[0];
// Tentukan ukuran file maksimum yang diizinkan. Unit: byte.
const maxFileSize = 1024 * 1024; // 1MB
// Tentukan jenis file yang diizinkan.
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
if (file) {
// Tentukan ukuran file.
if (file.size > maxFileSize) {
alert('Ukuran file melebihi batas. Ukuran file yang akan diunggah harus kurang dari 1 MB.');
return;
}
// Periksa jenis file.
if (!allowedTypes.includes(file.type)) {
alert ('Jenis file tidak didukung. Jenis file yang diizinkan adalah JPEG, PNG, dan PDF.');
return;
}
// File memenuhi persyaratan unggahan dan dapat diunggah.
// Tulis logika unggahan Anda.
console.log('Unggah file:', file.name);
// Tulis kode implementasi unggahan Anda.
} else {
alert('Pilih file untuk diunggah.');
}
}
</script>
</body>
</html>