A operação PostObject permite enviar arquivos diretamente de um cliente web para o Object Storage Service (OSS). Ela utiliza uma assinatura gerada no servidor para garantir a segurança e possibilita configurar uma política que restringe os uploads conforme as necessidades do seu negócio.
Visão geral da solução
Para implementar o upload direto com assinatura no servidor, siga estas três etapas:
O uso de uma credencial de acesso temporária evita a exposição da chave de longo prazo do seu servidor, aumentando a segurança no upload de arquivos.
Configure o OSS: Crie um bucket no console para armazenar os arquivos dos usuários. Em seguida, configure regras de Cross-Origin Resource Sharing (CORS) no bucket para permitir requisições de origem cruzada provenientes do cliente web.
Configure o servidor: Chame o Security Token Service (STS) para obter uma credencial de acesso temporária. Depois, utilize essa credencial e uma política de upload no servidor para gerar uma assinatura. Essa política inclui parâmetros como nome do bucket, caminho do diretório e tempo de expiração. A assinatura autoriza o usuário a enviar arquivos por um período determinado.
Configure o cliente web: Construa uma requisição de formulário HTML e use a assinatura para enviar o arquivo ao OSS.
Projetos de exemplo
Para o projeto de exemplo em Java, consulte server-signed-direct-upload-java.zip.
Para o projeto de exemplo em Python, consulte server-signed-direct-upload-python.zip.
Para o projeto de exemplo em Node.js, consulte server-signed-direct-upload-nodejs.zip.
Para o projeto de exemplo em Go, consulte server-signed-direct-upload-go.zip.
Para o projeto de exemplo em PHP, consulte server-signed-direct-upload-php.zip.
Etapas
Etapa 1: Configurar o OSS
Criar um bucket
Crie um bucket do OSS para armazenar os arquivos enviados diretamente pelo navegador web.
Faça login no console do OSS.
No painel de navegação à esquerda, clique em Buckets, e depois clique em Create Bucket.
-
No painel Create Bucket, selecione Quick Create e configure os seguintes parâmetros:
Parâmetro
Valor de exemplo
Bucket Name
web-direct-upload
Region
China (Hangzhou)
Clique em Create.
Configurar uma regra CORS
Configure uma regra CORS para o seu bucket do OSS.
Na página Buckets, clique no bucket desejado.
Na página CORS, clique em Create Rule.
-
No painel Create Rule, defina os seguintes parâmetros.
Parâmetro
Valor de exemplo
Origin
*
Allowed Methods
POST, PUT, GET
Allowed Headers
*
Clique em OK.
Etapa 2: Configurar o servidor
Em um ambiente de produção, caso você já possua um servidor, pule as preparações e vá diretamente para 1. Configure user permissions.
Criar uma instância ECS
Etapa 1: Criar uma instância ECS
Acesse a página Custom Launch e selecione os recursos básicos necessários para criar uma instância ECS.
-
Selecione uma região e um método de faturamento
Escolha um método de faturamento adequado às necessidades do seu negócio. Este tutorial utiliza o modo pay-as-you-go devido à sua flexibilidade.
-
Geralmente, escolher uma região mais próxima dos seus usuários resulta em menor latência de rede e acesso mais rápido. Este tutorial usa China (Hangzhou) como exemplo.
Para Billing Method, selecione pay-as-you-go (pós-pago e sob demanda). Instâncias pay-as-you-go não suportam registro ICP. Após a criação da instância, não é possível alterar sua região. Instâncias em regiões diferentes não podem se comunicar pela rede interna.
-
Crie uma Virtual Private Cloud (VPC) e um vSwitch
Ao criar uma VPC, selecione a mesma região da instância ECS e planeje os blocos CIDR conforme as necessidades do seu negócio. Este tutorial exemplifica a criação de uma VPC e de um vSwitch na região China (Hangzhou). Após criar a VPC e o vSwitch, retorne à página de compra do ECS, atualize-a e selecione-os.
NotaÉ possível criar um vSwitch durante a criação da VPC.
Na página Create VPC, defina Name como ProjectA-VPC, selecione Manually Specify IPv4 CIDR Block para IPv4 CIDR Block e insira
192.168.0.0/16, e selecione Do Not Assign para IPv6 CIDR Block.Exemplo de configuração do vSwitch: Defina Name como ProjectA-vSwitch, selecione Hangzhou Zone H para Zone, defina o IPv4 CIDR Block como
192.168.10.0/24e clique em OK.
-
Selecione um tipo de instância e uma imagem
Escolha o tipo de instância e a imagem. A imagem determina o sistema operacional e a versão instalados na instância. Este tutorial utiliza o tipo de instância
ecs.e-c1m1.large, que é econômico e atende aos requisitos de teste. A imagem utilizada é a imagem públicaAlibaba Cloud Linux 3.2104 LTS 64-bit.
-
Configure o armazenamento
Para o sistema web simples deste tutorial, um disco de sistema é suficiente para o sistema operacional, portanto, não é necessário um disco de dados.
Para o disco de sistema, selecione ESSD, defina Performance Level como PL0 e Capacity como 40 GiB, selecione Release with Instance e não adicione um disco de dados.
-
Atribua um endereço IP público
Para simplificar, este tutorial atribui um endereço IP público diretamente à instância. Alternativamente, você pode associar um Elastic IP Address (EIP) à instância após criá-la. Para mais informações, consulte Associate an EIP with a cloud resource.
NotaSem um endereço IP público atribuído, não é possível usar SSH ou Remote Desktop Protocol (RDP) para acessar a instância diretamente pela internet, nem verificar a implantação do service web nela.
Este tutorial utiliza o método de faturamento de largura de banda pay-by-traffic. Esse método cobra apenas pelo tráfego público consumido. Para mais informações, consulte Public bandwidth billing.
Defina Peak bandwidth como 5 Mbps.
-
Crie um grupo de segurança
Crie um grupo de segurança para a instância. Um grupo de segurança atua como um firewall virtual que controla o tráfego de entrada e saída de uma instância ECS. Ao criar o grupo de segurança, permita o tráfego nas portas listadas abaixo para possibilitar o acesso futuro à instância ECS.
Port range: SSH (22), RDP (3389), HTTP (80) e HTTPS (443).
NotaAs portas selecionadas em Port range são necessárias para as aplicações executadas na instância ECS.
Por padrão, o grupo de segurança criado aqui inclui uma regra que define a origem como 0.0.0.0/0. Isso permite acesso de qualquer endereço IP às portas especificadas. Se você souber os endereços IP dos clientes solicitantes, recomendamos restringir posteriormente a origem a um intervalo específico de IPs. Para mais informações, consulte Modify a security group rule.
Na seção Security group type, selecione Basic security group.
-
Crie um par de chaves
Um par de chaves fornece credenciais de login seguras. Após criar um par de chaves, baixe sua chave privada, necessária para connect to an ECS instance. Em seguida, retorne à página de compra do ECS, atualize-a e selecione o par de chaves.
-
O usuário
rootpossui os privilégios mais altos no sistema operacional, e o uso derootcomo nome de login pode causar riscos de segurança. Recomendamos utilizarecs-usercomo nome de login.NotaApós a criação do par de chaves, a chave privada é baixada automaticamente. Salve o arquivo de chave privada
.pemno histórico de downloads do seu navegador.Na seção Logon Credential, selecione a aba Key pair e clique em Create key pair. Depois, selecione o par de chaves recém-criado (por exemplo,
ecs-test) na lista suspensa Key pair.
-
Crie e visualize a instância ECS
Após selecionar os recursos necessários para a instância ECS, clique em Create order. Na caixa de diálogo de sucesso, clique em Management console para visualizar a nova instância. Salve as informações abaixo para uso posterior:
Instance ID: Usado para localizar a instância na lista de instâncias.
Region: Usada para localizar a instância na lista de instâncias.
Public IP address: Usado para verificar a implantação do service web.
Etapa 2: Conectar-se à instância ECS
Na página Instances do console do ECS, localize sua instância usando a região e o ID e, na coluna Actions, clique em Connect.
Na caixa de diálogo Remote connection, clique em Sign in now ao lado de Workbench.
Na caixa de diálogo Log on to instance, selecione Terminal connection para Connection method e SSH key authentication para Authentication method. Em seguida, insira ou envie seu arquivo de chave privada e clique em Log on para conectar-se como o usuário
ecs-user.-
Nota
O arquivo de chave privada (
.pem) é baixado automaticamente para o seu dispositivo quando você cria o par de chaves. Verifique o histórico de downloads do seu navegador para encontrar o arquivo. -
Quando a seguinte saída for exibida, o login na instância ECS terá sido realizado com sucesso.
Welcome to Alibaba Cloud Elastic Compute Service ! Last login: Sun Sep 29 15:35:22 2024 from xxx [ecs-user@iz*** ~]$
Permissões de usuário
Para evitar falhas nos uploads do OSS após a implantação devido a permissões insuficientes, crie um usuário RAM e configure as permissões necessárias.
Etapa 1: Criar um usuário RAM
Crie um usuário RAM e obtenha seu par AccessKey para servir como credencial de longo prazo para o servidor da sua aplicação.
Faça login no console do RAM com sua conta Alibaba Cloud ou como administrador RAM.
No painel de navegação à esquerda, escolha Identities > Users.
Clique em Create User.
Insira um Logon Name e um Display Name.
Na seção Access Mode, selecione Programmatic access e clique em OK.
O AccessKey secret é exibido apenas no momento da criação e não pode ser recuperado posteriormente. Armazene-o com segurança.
Na coluna Actions, clique em Copy para salvar o par AccessKey (AccessKey ID e AccessKey secret).
Etapa 2: Conceder permissão AssumeRole
Após criar o usuário RAM, conceda a ele permissão para chamar a operação AssumeRole do STS. Isso permite que o usuário obtenha credenciais temporárias assumindo uma função RAM.
No painel de navegação à esquerda, escolha Identities > Users.
Na página Users, localize o usuário RAM desejado e clique em Add Permissions na coluna Actions.
-
Na página Grant Permission, selecione a Política de Sistema AliyunSTSAssumeRoleAccess.
NotaA política AliyunSTSAssumeRoleAccess concede permissão para chamar a operação
AssumeRole. Ela não concede permissões para operações subsequentes que utilizem as credenciais temporárias, como requisições ao OSS. Clique em OK.
Etapa 3: Criar uma função RAM
Crie uma função RAM para a conta Alibaba Cloud atual e obtenha seu Alibaba Cloud Resource Name (ARN). O usuário RAM assumirá essa função.
No painel de navegação à esquerda, escolha Identities > Roles.
Clique em Create Role. Para Principal Type, selecione Alibaba Cloud Account.
Selecione a conta Alibaba Cloud atual e clique em OK.
Insira um nome para a função e clique em OK.
Na página de detalhes da função RAM, clique em Copy para salvar o ARN da função.
Etapa 4: Criar uma política de upload de arquivos
Seguindo o princípio do menor privilégio, crie uma Política Personalizada para a função RAM que restrinja os uploads a um bucket específico do OSS.
No painel de navegação à esquerda, escolha Permissions > Policies.
Clique em Create Policy.
-
Na página Create Policy, clique em JSON Editor e substitua
<Bucket name>no script pelo nome do bucketweb-direct-uploadcriado na seção de Preparações.{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "oss:PutObject", "Resource": "acs:oss:*:*:<BucketName>/*" } ] } Após configurar a política, clique em OK.
Na caixa de diálogo Create Policy, insira um Policy Name e clique em OK.
Etapa 5: Conceder permissões à função RAM
Anexe a Política Personalizada criada à função RAM. Isso fornece à função assumida as permissões necessárias.
No painel de navegação à esquerda, escolha Identities > Roles.
Na página Roles, localize a função RAM desejada e clique em Add Permissions na coluna Actions.
Na página Grant Permission, selecione Custom Policy e escolha a política que você criou.
Clique em OK.
Assinatura no servidor
Recomendamos configurar informações sensíveis, como AccessKey ID, AccessKey Secret e Role ARN, como variáveis de ambiente. Essa prática evita codificá-las diretamente no código e reduz o risco de vazamento de credenciais.
Siga estas etapas para definir as variáveis de ambiente.
Linux
-
Na linha de comando, execute os comandos abaixo para anexar as definições das variáveis de ambiente ao arquivo
~/.bashrc.echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.bashrc echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.bashrc echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.bashrc -
Execute o comando a seguir para aplicar as alterações.
source ~/.bashrc -
Execute os comandos abaixo para verificar se as variáveis de ambiente foram definidas.
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
macOS
-
No terminal, execute o comando a seguir para verificar seu shell padrão.
echo $SHELL -
Siga as instruções correspondentes ao seu shell padrão.
Zsh
-
Execute os comandos abaixo para anexar as definições das variáveis de ambiente ao arquivo
~/.zshrc.echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.zshrc echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.zshrc echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.zshrc -
Execute o comando a seguir para aplicar as alterações.
source ~/.zshrc -
Execute os comandos abaixo para verificar se as variáveis de ambiente foram definidas.
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
Bash
-
Execute os comandos abaixo para anexar as definições das variáveis de ambiente ao arquivo
~/.bash_profile.echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.bash_profile echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.bash_profile echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.bash_profile -
Execute o comando a seguir para aplicar as alterações.
source ~/.bash_profile -
Execute os comandos abaixo para verificar se as variáveis de ambiente foram definidas.
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
-
Windows
-
Execute os comandos a seguir no Prompt de Comando (CMD).
setx OSS_ACCESS_KEY_ID "your-access-key-id" setx OSS_ACCESS_KEY_SECRET "your-access-key-secret" setx OSS_STS_ROLE_ARN "your-role-arn" Abra uma nova janela do CMD.
-
Na nova janela do CMD, execute os comandos abaixo para verificar se as variáveis de ambiente foram definidas.
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET% echo %OSS_STS_ROLE_ARN%
Utilize o código de exemplo a seguir para calcular uma assinatura POST no servidor com Signature Version 4 (recommended). Para mais informações sobre a configuração do campo de formulário policy, consulte policy form field.
Java
Adicione as seguintes dependências ao seu projeto Maven.
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>sts20150401</artifactId>
<version>1.1.6</version>
</dependency>
O código de exemplo a seguir mostra como obter uma credencial de acesso temporária e calcular uma assinatura POST no servidor:
package com.aliyun.oss.web;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Controller
public class WebController {
// Basic OSS information. Replace with your actual bucket name, region ID, and host.
String bucket = "examplebucket";
String region = "cn-hangzhou";
String host = "http://examplebucket.oss-cn-hangzhou.aliyuncs.com";
// Set the upload callback URL, which is the address of your callback server. This must be a public URL. OSS uses this URL to send object upload information to your application server.
// The prefix (directory) for objects to be uploaded to OSS.
String upload_dir = "dir";
// The expiration time in seconds.
Long expire_time = 3600L;
/**
* Generates an expiration time based on a specified duration in seconds.
* @param seconds The duration in seconds.
* @return An ISO 8601 time string, such as "2014-12-01T12:00:00.000Z".
*/
public static String generateExpiration(long seconds) {
// Get the current timestamp in seconds.
long now = Instant.now().getEpochSecond();
// Calculate the expiration timestamp.
long expirationTime = now + seconds;
// Convert the timestamp to an Instant object and format it to ISO 8601.
Instant instant = Instant.ofEpochSecond(expirationTime);
// Define the time zone as UTC.
ZoneId zone = ZoneOffset.UTC;
// Convert the Instant to a ZonedDateTime.
ZonedDateTime zonedDateTime = instant.atZone(zone);
// Define the date-time format, for example, 2023-12-03T13:00:00.000Z.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
// Format the date and time.
String formattedDate = zonedDateTime.format(formatter);
// Return the result.
return formattedDate;
}
// Initialize the STS client.
public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
// Hardcoding an AccessKey pair is a security risk and not recommended. This code is for reference only.
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// Required. Make sure that the OSS_ACCESS_KEY_ID environment variable is set in your code's runtime environment.
.setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID"))
// Required. Make sure that the OSS_ACCESS_KEY_SECRET environment variable is set in your code's runtime environment.
.setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET"));
// For more information about endpoints, see https://api.alibabacloud.com/product/Sts.
config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
return new com.aliyun.sts20150401.Client(config);
}
/**
* Obtain an STS temporary credential.
* @return An AssumeRoleResponseBodyCredentials object.
*/
public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception {
com.aliyun.sts20150401.Client client = WebController.createStsClient();
com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
// Required. Make sure that the OSS_STS_ROLE_ARN environment variable is set in your code's runtime environment.
.setRoleArn(System.getenv("OSS_STS_ROLE_ARN"))
.setRoleSessionName("yourRoleSessionName");// A custom session name.
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// If you copy this code to run, print the API return value.
AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
// The credentials object contains the AccessKeyId, AccessKeySecret, and SecurityToken.
return response.body.credentials;
} catch (TeaException error) {
// This is for demonstration only. Handle exceptions with caution and do not ignore them in your project.
// Error message
System.out.println(error.getMessage());
// Diagnostic address
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
// Return a default error response object to avoid returning null.
AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials defaultCredentials = new AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials();
defaultCredentials.accessKeyId = "ERROR_ACCESS_KEY_ID";
defaultCredentials.accessKeySecret = "ERROR_ACCESS_KEY_SECRET";
defaultCredentials.securityToken = "ERROR_SECURITY_TOKEN";
return defaultCredentials;
}
@GetMapping("/get_post_signature_for_oss_upload")
public ResponseEntity<Map<String, String>> getPostSignatureForOssUpload() throws Exception {
AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials sts_data = getCredential();
String accesskeyid = sts_data.accessKeyId;
String accesskeysecret = sts_data.accessKeySecret;
String securitytoken = sts_data.securityToken;
// Get the date for x-oss-credential. This is the current date in yyyyMMdd format.
ZonedDateTime today = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String date = today.format(formatter);
// Get x-oss-date.
ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
String x_oss_date = now.format(formatter2);
// Step 1: Create a policy.
String x_oss_credential = accesskeyid + "/" + date + "/" + region + "/oss/aliyun_v4_request";
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> policy = new HashMap<>();
policy.put("expiration", generateExpiration(expire_time));
List<Object> conditions = new ArrayList<>();
Map<String, String> bucketCondition = new HashMap<>();
bucketCondition.put("bucket", bucket);
conditions.add(bucketCondition);
Map<String, String> securityTokenCondition = new HashMap<>();
securityTokenCondition.put("x-oss-security-token", securitytoken);
conditions.add(securityTokenCondition);
Map<String, String> signatureVersionCondition = new HashMap<>();
signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
conditions.add(signatureVersionCondition);
Map<String, String> credentialCondition = new HashMap<>();
credentialCondition.put("x-oss-credential", x_oss_credential); // Replace with your actual AccessKey ID.
conditions.add(credentialCondition);
Map<String, String> dateCondition = new HashMap<>();
dateCondition.put("x-oss-date", x_oss_date);
conditions.add(dateCondition);
conditions.add(Arrays.asList("content-length-range", 1, 10240000));
conditions.add(Arrays.asList("eq", "$success_action_status", "200"));
conditions.add(Arrays.asList("starts-with", "$key", upload_dir));
policy.put("conditions", conditions);
String jsonPolicy = mapper.writeValueAsString(policy);
// Step 2: Construct the string to sign.
String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
// System.out.println("stringToSign: " + stringToSign);
// Step 3: Calculate the signing key.
byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), date);
byte[] dateRegionKey = hmacsha256(dateKey, region);
byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
// System.out.println("signingKey: " + BinaryUtil.toBase64String(signingKey));
// Step 4: Calculate the signature.
byte[] result = hmacsha256(signingKey, stringToSign);
String signature = BinaryUtil.toHex(result);
// System.out.println("signature:" + signature);
Map<String, String> response = new HashMap<>();
// Add the data to the map.
response.put("version", "OSS4-HMAC-SHA256");
response.put("policy", stringToSign);
response.put("x_oss_credential", x_oss_credential);
response.put("x_oss_date", x_oss_date);
response.put("signature", signature);
response.put("security_token", securitytoken);
response.put("dir", upload_dir);
response.put("host", host);
// Return a ResponseEntity with status code 200 (OK) to the web client for the PostObject operation.
return ResponseEntity.ok(response);
}
public static byte[] hmacsha256(byte[] key, String data) {
try {
// Initialize the HmacSHA256 key specification.
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
// Get an HmacSHA256 Mac instance.
Mac mac = Mac.getInstance("HmacSHA256");
// Initialize the Mac object with the key.
mac.init(secretKeySpec);
// Calculate the HMAC signature for the data.
byte[] hmacBytes = mac.doFinal(data.getBytes());
return hmacBytes;
} catch (Exception e) {
throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
}
}
}
Python
Execute os comandos a seguir para instalar as dependências.
pip install flask
pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials
O código de exemplo a seguir mostra como obter uma credencial de acesso temporária (token STS), construir uma política de upload e calcular uma assinatura POST no servidor.
from flask import Flask, render_template, jsonify
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
from alibabacloud_credentials.client import Client as CredentialClient
import os
import json
import base64
import hmac
import datetime
import time
import hashlib
app = Flask(__name__)
# Configure the OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, and OSS_STS_ROLE_ARN environment variables.
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
role_arn_for_oss_upload = os.environ.get('OSS_STS_ROLE_ARN')
# A custom session name.
role_session_name = 'yourRoleSessionName'
# Replace with your actual bucket name, region ID, and host.
bucket = 'examplebucket'
region_id = 'cn-hangzhou'
host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'
# The expiration time in seconds.
expire_time = 3600
# The prefix (directory) for objects to be uploaded to OSS.
upload_dir = 'dir'
def hmacsha256(key, data):
"""
Calculates the HMAC-SHA256 hash value.
:param key: The key for calculating the hash, in bytes.
:param data: The data to be hashed, as a string.
:return: The calculated HMAC-SHA256 hash value, in bytes.
"""
try:
mac = hmac.new(key, data.encode(), hashlib.sha256)
hmacBytes = mac.digest()
return hmacBytes
except Exception as e:
raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")
@app.route("/")
def hello_world():
return render_template('index.html')
@app.route('/get_post_signature_for_oss_upload', methods=['GET'])
def generate_upload_params():
# Initialize the configuration and pass the credentials directly.
config = Config(
region_id=region_id,
access_key_id=access_key_id,
access_key_secret=access_key_secret
)
# Create an STS client and obtain a temporary credential.
sts_client = Sts20150401Client(config=config)
assume_role_request = sts_20150401_models.AssumeRoleRequest(
role_arn=role_arn_for_oss_upload,
role_session_name=role_session_name
)
response = sts_client.assume_role(assume_role_request)
token_data = response.body.credentials.to_map()
# Use the temporary credential returned by STS.
temp_access_key_id = token_data['AccessKeyId']
temp_access_key_secret = token_data['AccessKeySecret']
security_token = token_data['SecurityToken']
now = int(time.time())
# Convert the timestamp to a datetime object.
dt_obj = datetime.datetime.utcfromtimestamp(now)
# Add 3 hours to the current time to set the request expiration time.
dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
# Request time.
dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
# Request date.
dt_obj_2 = dt_obj.strftime('%Y%m%d')
# Request expiration time.
expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
# Construct the policy and generate the signature.
policy = {
"expiration": expiration_time,
"conditions": [
["eq", "$success_action_status", "200"],
{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
{"x-oss-credential": f"{temp_access_key_id}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},
{"x-oss-security-token": security_token},
{"x-oss-date": dt_obj_1},
]
}
print(dt_obj_1)
policy_str = json.dumps(policy).strip()
# Step 2: Construct the string to sign.
stringToSign = base64.b64encode(policy_str.encode()).decode()
# Step 3: Calculate the signing key.
dateKey = hmacsha256(("aliyun_v4" + temp_access_key_secret).encode(), dt_obj_2)
dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")
dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
# Step 4: Calculate the signature.
result = hmacsha256(signingKey, stringToSign)
signature = result.hex()
# Construct the response data.
response_data = {
'policy': stringToSign, # The policy form field.
'x_oss_signature_version': "OSS4-HMAC-SHA256", # The signature version and algorithm. This is fixed to OSS4-HMAC-SHA256.
'x_oss_credential': f"{temp_access_key_id}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request", # Specifies the credential scope.
'x_oss_date': dt_obj_1, # The request time.
'signature': signature, # The calculated signature.
'host': host,
'dir': upload_dir,
'security_token': security_token # The security token.
}
return jsonify(response_data)
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000) # If you need to listen on other addresses such as 0.0.0.0, you must add a server-side authentication mechanism.
Node.js
Execute os comandos a seguir para instalar as dependências.
npm install ali-oss
npm install @alicloud/credentials
npm install express
O código de exemplo a seguir mostra como obter uma credencial de acesso temporária (token STS), construir uma política de upload e calcular uma assinatura POST no servidor.
const express = require('express');
const OSS = require('ali-oss');
const { STS } = require('ali-oss');
const { getCredential } = require('ali-oss/lib/common/signUtils');
const { getStandardRegion } = require('ali-oss/lib/common/utils/getStandardRegion');
const { policy2Str } = require('ali-oss/lib/common/utils/policy2Str');
const app = express();
const PORT = process.env.PORT || 8000; // The port number for service requests.
// Set the static file directory.
app.use(express.static('templates'));
const GenerateSignature = async () => {
// Initialize the STS client.
let sts = new STS({
accessKeyId: process.env.OSS_ACCESS_KEY_ID, // Get the AccessKey ID of the RAM user from the environment variable.
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET // Get the AccessKey Secret of the RAM user from the environment variable.
});
// Call the assumeRole operation to obtain a temporary STS access credential.
const result = await sts.assumeRole(process.env.OSS_STS_ROLE_ARN, '', '3600', 'yourRoleSessionName'); // Get the RAM role ARN from the environment variable. The temporary access credential is valid for 3,600 seconds, and the role session name is a custom value, such as yourRoleSessionName.
// Extract the AccessKeyId, AccessKeySecret, and SecurityToken from the temporary access credential.
const accessKeyId = result.credentials.AccessKeyId;
const accessKeySecret = result.credentials.AccessKeySecret;
const securityToken = result.credentials.SecurityToken;
// Initialize the OSS client.
const client = new OSS({
bucket: 'examplebucket', // Replace with the name of the destination bucket.
region: 'cn-hangzhou', // Replace with the region of the destination bucket.
accessKeyId,
accessKeySecret,
stsToken: securityToken,
refreshSTSTokenInterval: 0,
refreshSTSToken: async () => {
const { accessKeyId, accessKeySecret, securityToken } = await client.getCredential();
return { accessKeyId, accessKeySecret, stsToken: securityToken };
},
});
// Create a form data map.
const formData = new Map();
// Set the signature expiration time to 10 minutes from the current time.
const date = new Date();
const expirationDate = new Date(date);
expirationDate.setMinutes(date.getMinutes() + 10);
// Format the date to a UTC time string that complies with ISO 8601.
function padTo2Digits(num) {
return num.toString().padStart(2, '0');
}
function formatDateToUTC(date) {
return (
date.getUTCFullYear() +
padTo2Digits(date.getUTCMonth() + 1) +
padTo2Digits(date.getUTCDate()) +
'T' +
padTo2Digits(date.getUTCHours()) +
padTo2Digits(date.getUTCMinutes()) +
padTo2Digits(date.getUTCSeconds()) +
'Z'
);
}
const formattedDate = formatDateToUTC(expirationDate);
// Generate x-oss-credential and set the form data.
const credential = getCredential(formattedDate.split('T')[0], getStandardRegion(client.options.region), client.options.accessKeyId);
formData.set('x_oss_date', formattedDate);
formData.set('x_oss_credential', credential);
formData.set('x_oss_signature_version', 'OSS4-HMAC-SHA256');
// Create the policy.
// This example policy lists only the required conditions.
const policy = {
expiration: expirationDate.toISOString(),
conditions: [
{ 'bucket': 'examplebucket'},
{ 'x-oss-credential': credential },
{ 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
{ 'x-oss-date': formattedDate },
],
};
// If an STS token exists, add it to the policy and form data.
if (client.options.stsToken) {
policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
formData.set('security_token', client.options.stsToken);
}
// Generate the signature and set the form data.
const signature = client.signPostObjectPolicyV4(policy, date);
formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
formData.set('signature', signature);
// Return the form data.
return {
host: `http://${client.options.bucket}.oss-${client.options.region}.aliyuncs.com`,
policy: Buffer.from(policy2Str(policy), 'utf8').toString('base64'),
x_oss_signature_version: 'OSS4-HMAC-SHA256',
x_oss_credential: credential,
x_oss_date: formattedDate,
signature: signature,
dir: 'user-dir', // The prefix (directory) for the object to be uploaded to OSS.
security_token: client.options.stsToken
};
};
app.get('/get_post_signature_for_oss_upload', async (req, res) => {
try {
const result = await GenerateSignature();
res.json(result); // Return the generated signature data.
} catch (error) {
console.error('Error generating signature:', error);
res.status(500).send('Error generating signature');
}
});
app.listen(PORT, () => {
console.log(`Server is running on http://127.0.0.1:${PORT}`); // If you need to listen on other addresses such as 0.0.0.0, you must add a server-side authentication mechanism.
});
Go
Execute os comandos a seguir para instalar as dependências.
go get -u github.com/aliyun/credentials-go
go mod tidy
O código de exemplo a seguir mostra como obter uma credencial de acesso temporária (token STS), construir uma política de upload e calcular uma assinatura POST no servidor.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"hash"
"log"
"net/http"
"os"
"time"
"github.com/aliyun/credentials-go/credentials"
)
// Define global variables.
var (
region string
bucketName string
product = "oss"
)
// The PolicyToken struct stores the generated form data.
type PolicyToken struct {
Policy string `json:"policy"`
SecurityToken string `json:"security_token"`
SignatureVersion string `json:"x_oss_signature_version"`
Credential string `json:"x_oss_credential"`
Date string `json:"x_oss_date"`
Signature string `json:"signature"`
Host string `json:"host"`
Dir string `json:"dir"`
}
func main() {
// Define the default IP address and port string.
strIPPort := ":8000"
if len(os.Args) == 3 {
strIPPort = fmt.Sprintf("%s:%s", os.Args[1], os.Args[2])
} else if len(os.Args) != 1 {
fmt.Println("Usage : go run test1.go ")
fmt.Println("Usage : go run test1.go ip port ")
fmt.Println("")
os.Exit(0)
}
// Print the address and port on which the server is running.
fmt.Printf("server is running on %s \n", strIPPort)
// Register the function to handle root path requests.
http.HandleFunc("/", handlerRequest)
// Register the function to handle signature generation requests.
http.HandleFunc("/get_post_signature_for_oss_upload", handleGetPostSignature)
// Start the HTTP server.
err := http.ListenAndServe(strIPPort, nil)
if err != nil {
strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
panic(strError)
}
}
// The handlerRequest function handles root path requests.
func handlerRequest(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
http.ServeFile(w, r, "templates/index.html")
return
}
http.NotFound(w, r)
}
// The handleGetPostSignature function handles signature generation requests.
func handleGetPostSignature(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
response := getPolicyToken()
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // Allow cross-origin requests.
w.Write([]byte(response))
return
}
http.NotFound(w, r)
}
// The getPolicyToken function generates the signature and credentials required for OSS uploads.
func getPolicyToken() string {
// Set the region of the bucket.
region = "cn-hangzhou"
// Replace with your bucket name.
bucketName = "examplebucket"
// Set the OSS upload address.
host := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com", bucketName, region)
// Set the upload directory.
dir := "user-dir"
config := new(credentials.Config).
SetType("ram_role_arn").
SetAccessKeyId(os.Getenv("OSS_ACCESS_KEY_ID")).
SetAccessKeySecret(os.Getenv("OSS_ACCESS_KEY_SECRET")).
SetRoleArn("OSS_STS_ROLE_ARN").
SetRoleSessionName("Role_Session_Name").
SetPolicy("").
SetRoleSessionExpiration(3600)
// Create a credential provider based on the configuration.
provider, err := credentials.NewCredential(config)
if err != nil {
log.Fatalf("NewCredential fail, err:%v", err)
}
// Obtain credentials from the credential provider.
cred, err := provider.GetCredential()
if err != nil {
log.Fatalf("GetCredential fail, err:%v", err)
}
// Construct the policy.
utcTime := time.Now().UTC()
date := utcTime.Format("20060102")
expiration := utcTime.Add(1 * time.Hour)
policyMap := map[string]any{
"expiration": expiration.Format("2006-01-02T15:04:05.000Z"),
"conditions": []any{
map[string]string{"bucket": bucketName},
map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
map[string]string{"x-oss-credential": fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request", *cred.AccessKeyId, date, region, product)},
map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
map[string]string{"x-oss-security-token": *cred.SecurityToken},
},
}
// Convert the policy to JSON format.
policy, err := json.Marshal(policyMap)
if err != nil {
log.Fatalf("json.Marshal fail, err:%v", err)
}
// Construct the string to sign.
stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
hmacHash := func() hash.Hash { return sha256.New() }
// Construct the signing key.
signingKey := "aliyun_v4" + *cred.AccessKeySecret
h1 := hmac.New(hmacHash, []byte(signingKey))
io.WriteString(h1, date)
h1Key := h1.Sum(nil)
h2 := hmac.New(hmacHash, h1Key)
io.WriteString(h2, region)
h2Key := h2.Sum(nil)
h3 := hmac.New(hmacHash, h2Key)
io.WriteString(h3, product)
h3Key := h3.Sum(nil)
h4 := hmac.New(hmacHash, h3Key)
io.WriteString(h4, "aliyun_v4_request")
h4Key := h4.Sum(nil)
// Generate the signature.
h := hmac.New(hmacHash, h4Key)
io.WriteString(h, stringToSign)
signature := hex.EncodeToString(h.Sum(nil))
// Construct the form to be returned to the client.
policyToken := PolicyToken{
Policy: stringToSign,
SecurityToken: *cred.SecurityToken,
SignatureVersion: "OSS4-HMAC-SHA256",
Credential: fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request", *cred.AccessKeyId, date, region, product),
Date: utcTime.UTC().Format("20060102T150405Z"),
Signature: signature,
Host: host, // The OSS upload address.
Dir: dir, // The upload directory.
}
response, err := json.Marshal(policyToken)
if err != nil {
fmt.Println("json err:", err)
}
return string(response)
}
PHP
Execute o comando a seguir para instalar as dependências.
composer install
O código de exemplo a seguir mostra como obter uma credencial de acesso temporária (token STS), construir uma política de upload e calcular uma assinatura POST no servidor.
<?php
// Import the Alibaba Cloud SDK.
require_once __DIR__ . '/vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;
// Disable error display.
ini_set('display_errors', '0');
$bucket = 'examplebucket'; // Replace with your bucket name.
$region_id = 'cn-hangzhou'; // Replace with the region of your bucket.
$host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'; // Replace with your bucket's domain name.
$expire_time = 3600; // The expiration time in seconds.
$upload_dir = 'user-dir'; // The prefix (directory) for uploaded objects.
// Calculate HMAC-SHA256.
function hmacsha256($key, $data) {
return hash_hmac('sha256', $data, $key, true);
}
// Handle the request to get the POST signature.
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/get_post_signature_for_oss_upload') {
AlibabaCloud::accessKeyClient(getenv('OSS_ACCESS_KEY_ID'), getenv('OSS_ACCESS_KEY_SECRET'))
->regionId('cn-hangzhou')
->asDefaultClient();
// Create an STS request.
$request = Sts::v20150401()->assumeRole();
// Initiate the STS request and get the result.
// Set <YOUR_ROLE_SESSION_NAME> to a custom session name, such as oss-role-session.
// Replace <YOUR_ROLE_ARN> with the ARN of a RAM role that has permission to upload files to the specified OSS bucket.
$result = $request
->withRoleSessionName('oss-role-session')
->withDurationSeconds(3600)
->withRoleArn(getenv('OSS_STS_ROLE_ARN'))
->request();
// Get the credential information from the STS request result.
$tokenData = $result->get('Credentials');
// Construct the JSON data to return.
$tempAccessKeyId = $tokenData['AccessKeyId'];
$tempAccessKeySecret = $tokenData['AccessKeySecret'];
$securityToken = $tokenData['SecurityToken'];
$now = time();
$dtObj = gmdate('Ymd\THis\Z', $now);
$dtObj1 = gmdate('Ymd', $now);
$dtObjPlus3h = gmdate('Y-m-d\TH:i:s.u\Z', strtotime('+3 hours', $now));
// Construct the policy.
$policy = [
"expiration" => $dtObjPlus3h,
"conditions" => [
["x-oss-signature-version" => "OSS4-HMAC-SHA256"],
["x-oss-credential" => "{$tempAccessKeyId}/{$dtObj1}/cn-hangzhou/oss/aliyun_v4_request"],
["x-oss-security-token" => $securityToken],
["x-oss-date" => $dtObj],
]
];
$policyStr = json_encode($policy);
// Construct the string to sign.
$stringToSign = base64_encode($policyStr);
// Calculate the signing key.
$dateKey = hmacsha256(('aliyun_v4' . $tempAccessKeySecret), $dtObj1);
$dateRegionKey = hmacsha256($dateKey, 'cn-hangzhou');
$dateRegionServiceKey = hmacsha256($dateRegionKey, 'oss');
$signingKey = hmacsha256($dateRegionServiceKey, 'aliyun_v4_request');
// Calculate the signature.
$result = hmacsha256($signingKey, $stringToSign);
$signature = bin2hex($result);
// Return the signature data.
$responseData = [
'policy' => $stringToSign,
'x_oss_signature_version' => "OSS4-HMAC-SHA256",
'x_oss_credential' => "{$tempAccessKeyId}/{$dtObj1}/cn-hangzhou/oss/aliyun_v4_request",
'x_oss_date' => $dtObj,
'signature' => $signature,
'host' => $host,
'dir' => $upload_dir,
'security_token' => $securityToken
];
header('Content-Type: application/json');
echo json_encode($responseData);
exit;
}
// Home page route.
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/') {
echo file_get_contents(__DIR__ . '/public/index.html');
exit;
}
// Other routes.
http_response_code(404);
echo json_encode(['message' => 'Not Found']);
exit;
?>
Etapa 3: Configurar o cliente web
Upload via formulário no cliente
Depois que o cliente web recebe as informações necessárias do servidor da aplicação, ele constrói uma requisição de formulário HTML. Essa requisição se comunica diretamente com o OSS para enviar o arquivo.
Cliente web: Resposta de exemplo
O servidor da aplicação retorna o token STS e a política de upload para o cliente web.
{
"dir": "user-dirs",
"host": "http://examplebucket.oss-cn-hangzhou.aliyuncs.com",
"policy": "eyJl****",
"security_token": "CAIS****",
"signature": "9103****",
"x_oss_credential": "STS.NSpW****/20241127/cn-hangzhou/oss/aliyun_v4_request",
"x_oss_date": "20241127T060941Z",
"x_oss_signature_version": "OSS4-HMAC-SHA256"
}
A tabela a seguir descreve cada campo no corpo da resposta.
|
Parâmetro |
Descrição |
|
dir |
Especifica o prefixo obrigatório do nome do objeto para uploads. |
|
host |
O nome de domínio do bucket de destino. |
|
policy |
A política usada para uploads de formulário baseados em navegador. Para mais informações, consulte Post Policy. |
|
security_token |
A credencial temporária usada para autenticação, fornecida pelo STS. |
|
signature |
A assinatura gerada a partir da política. Para mais informações, consulte Post Signature. |
|
x_oss_credential |
Especifica o conjunto de parâmetros usado para derivar a chave de assinatura. |
|
x_oss_date |
O horário da requisição no formato ISO 8601, por exemplo, |
|
x_oss_signature_version |
A versão e o algoritmo da assinatura. O valor é fixo em OSS4-HMAC-SHA256. |
A requisição de formulário inclui o conteúdo do arquivo e os parâmetros retornados pelo servidor da aplicação.
Com essa requisição, o cliente web se comunica diretamente com o OSS para enviar o arquivo.
Exceto pelo campo de formulário file, todos os outros campos, incluindo key, não devem exceder 8 KB.
Por padrão, uploads via web sobrescrevem objetos com o mesmo nome. Para evitar isso, adicione o campo de formulário x-oss-forbid-overwrite à requisição e defina seu valor como true. Se já existir um objeto com o mesmo nome no OSS, o upload falhará e o OSS retornará um erro FileAlreadyExists.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generate a signature on the server to upload a file to OSS</title>
</head>
<body>
<div class="container">
<form>
<div class="mb-3">
<label for="file" class="form-label">Select a file:</label>
<input type="file" class="form-control" id="file" name="file" required />
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
const form = document.querySelector("form");
const fileInput = document.querySelector("#file");
form.addEventListener("submit", (event) => {
event.preventDefault();
const file = fileInput.files[0];
if (!file) {
alert('Please select a file to upload.');
return;
}
const filename = file.name;
fetch("/get_post_signature_for_oss_upload", { method: "GET" })
.then((response) => {
if (!response.ok) {
throw new Error("Failed to get signature");
}
return response.json();
})
.then((data) => {
let formData = new FormData();
formData.append("success_action_status", "200");
formData.append("policy", data.policy);
formData.append("x-oss-signature", data.signature);
formData.append("x-oss-signature-version", "OSS4-HMAC-SHA256");
formData.append("x-oss-credential", data.x_oss_credential);
formData.append("x-oss-date", data.x_oss_date);
formData.append("key", data.dir + file.name); // Object name
formData.append("x-oss-security-token", data.security_token);
formData.append("file", file); // file must be the last form field
return fetch(data.host, {
method: "POST",
body: formData
});
})
.then((response) => {
if (response.ok) {
console.log("Upload successful.");
alert("The file was uploaded successfully.");
} else {
console.log("Upload failed", response);
alert("Upload failed. Please try again later.");
}
})
.catch((error) => {
console.error("An error occurred:", error);
});
});
});
</script>
</body>
</html>
O formulário HTML contém um campo de entrada de arquivo e um botão de envio.
Ao submeter o formulário, o código JavaScript impede o envio padrão e envia uma requisição AJAX ao servidor da aplicação para obter as informações de assinatura necessárias.
Após receber as informações de assinatura, o código cria um objeto
FormDatacom os campos de formulário obrigatórios.Em seguida, utiliza o método
fetchpara enviar uma requisição POST à URL do OSS e enviar o arquivo.
Se o upload for bem-sucedido, a mensagem "The file was uploaded successfully." será exibida. Caso contrário, uma mensagem de erro aparecerá.
Verificação
Após a implantação, acesse seu servidor da aplicação para testar o recurso de upload direto com URLs assinadas.
Em um navegador, acesse seu servidor da aplicação. Clique em Select File, escolha um arquivo e faça o upload.
Na página Buckets, abra o bucket criado e verifique se o objeto enviado está presente.
Configurações recomendadas
Política de upload de arquivos
É possível modificar a policy no seu código para definir permissões e restrições para uploads de arquivos ao OSS a partir de um formulário HTML. A política em formato JSON permite restringir uploads definindo parâmetros como nome do bucket permitido, prefixo do objeto, tempo de expiração, métodos HTTP permitidos, limites de tamanho de conteúdo e tipos de conteúdo.
{
"expiration": "2023-12-03T13:00:00.000Z",
"conditions": [
{"bucket": "examplebucket"},
{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
{"x-oss-credential": "AKIDEXAMPLE/20231203/cn-hangzhou/oss/aliyun_v4_request"},
{"x-oss-security-token": "CAIS******"},
{"x-oss-date": "20231203T121212Z"},
["content-length-range", 1, 10],
["eq", "$success_action_status", "201"],
["starts-with", "$key", "user/eric/"],
["in", "$content-type", ["image/jpeg", "image/png"]],
["not-in", "$cache-control", ["no-cache"]]
]
}
Para mais informações sobre os parâmetros da política, consulte Post Policy.
Assinatura no servidor e callback de upload
Para receber metadados sobre os arquivos enviados, como nome e tamanho, configure um callback de upload. Após o upload de um arquivo, o OSS envia as informações do arquivo para o servidor da sua aplicação. Para mais informações, consulte Server-side signing and direct upload with an upload callback.
Restringir origens CORS
Para simplificar, a origem permitida foi definida anteriormente como o caractere curinga *. Como melhor prática de segurança, substitua o curinga pela URL específica do seu servidor da aplicação. Isso garante que apenas requisições de origem cruzada provenientes do seu servidor sejam autorizadas.
|
Parâmetro |
Valor de exemplo |
|
Origin |
|
|
Allowed Methods |
POST, PUT, GET |
|
Allowed Headers |
* |
Limpar recursos
Nesta solução, você criou uma instância ECS, um bucket OSS, um usuário RAM e uma função RAM. Após concluir os testes, limpe esses recursos para evitar cobranças contínuas ou riscos de segurança.
Liberar a instância ECS
Se não precisar mais da instância, libere-a. Após a liberação, o faturamento é interrompido e não é possível recuperar seus dados.
Acesse a página Instances no console do ECS. Localize a instância ECS desejada pela região e pelo ID da instância e clique em
na coluna Actions.Escolha Release. No menu exibido, clique em Release.
Confirme os detalhes da instância, selecione Release Now e clique em Next.
Revise os recursos associados que serão liberados, reconheça os riscos relacionados aos dados e clique em Confirm.
O disco de sistema e qualquer endereço IP público atribuído são liberados junto com a instância.
Grupos de segurança, vSwitches e VPCs não são liberados com a instância. Esses recursos são gratuitos, mas podem ser excluídos se não forem mais necessários.
EIPs não são liberados com a instância e continuam a gerar cobranças. Exclua-os separadamente se não forem mais necessários.
Excluir o bucket OSS
Faça login no console do OSS.
Clique em Buckets e, em seguida, clique no nome do bucket OSS desejado.
Exclua todos os objetos no bucket.
No painel de navegação à esquerda, clique em Delete Bucket e siga as instruções na tela.
Excluir o usuário RAM
Faça login no console do RAM como um usuário RAM com privilégios de administrador.
No painel de navegação à esquerda, escolha .
-
Na página Users, localize o usuário RAM desejado e clique em Delete na coluna Actions.
Alternativamente, selecione vários usuários RAM e clique em Delete User abaixo da lista para movê-los todos para a Lixeira.
Na caixa de diálogo Delete User, revise cuidadosamente o impacto da exclusão, insira o nome do usuário RAM desejado e clique em Move to Recycle Bin.
Excluir a função RAM
Faça login no console do RAM como um usuário RAM com privilégios de administrador.
No painel de navegação à esquerda, escolha .
Na página Roles, localize a função RAM desejada e clique em Delete Role na coluna Actions.
-
Na caixa de diálogo Delete Role, insira o nome da função RAM e clique em Delete Role.
NotaSe a função RAM tiver políticas anexadas, a exclusão da função também as desanexará.
FAQ
Upload multipartido e retomável
Esta solução utiliza upload via formulário e não suporta uploads multipartidos ou retomáveis. Para usar esses métodos, consulte Resumable upload e Multipart upload.
Evitar sobrescrita de arquivos
Defina o parâmetro x-oss-forbid-overwrite como true nos campos do formulário de upload. Por exemplo:
formData.append('x-oss-forbid-overwrite', 'true');