本文目录导读:

在PHP项目中生成临时凭证(直传签名),通常用于阿里云OSS、腾讯云COS或AWS S3等云存储服务的客户端直传场景,以下是几种常见云服务的实现方式:
阿里云OSS 直传签名
使用STS临时凭证(推荐)
<?php
use OSS\OssClient;
use OSS\Core\OssException;
require_once 'vendor/autoload.php';
// 配置
$accessKeyId = 'your-access-key-id';
$accessKeySecret = 'your-access-key-secret';
$roleArn = 'acs:ram::123456789:role/oss-upload-role'; // RAM角色ARN
$bucket = 'your-bucket';
$region = 'oss-cn-hangzhou';
try {
$ossClient = new OssClient($accessKeyId, $accessKeySecret, "https://sts.{$region}.aliyuncs.com");
// 申请临时凭证
$response = $ossClient->assumeRole($roleArn, 'session-name-'.time(), 3600);
$tempCredentials = [
'accessKeyId' => $response['Credentials']['AccessKeyId'],
'accessKeySecret' => $response['Credentials']['AccessKeySecret'],
'securityToken' => $response['Credentials']['SecurityToken'],
'expiration' => $response['Credentials']['Expiration'],
'region' => $region,
'bucket' => $bucket
];
echo json_encode($tempCredentials);
} catch (OssException $e) {
echo json_encode(['error' => $e->getMessage()]);
}
简单上传签名(不使用STS)
<?php
function getOssUploadSignature($bucket, $object, $expiration = 3600) {
$accessKeyId = 'your-access-key-id';
$accessKeySecret = 'your-access-key-secret';
$region = 'oss-cn-hangzhou';
$host = "{$bucket}.{$region}.aliyuncs.com";
$expireTime = time() + $expiration;
$expirationGmt = gmdate('Y-m-d\TH:i:s\Z', $expireTime);
$policy = [
'expiration' => $expirationGmt,
'conditions' => [
['bucket' => $bucket],
['eq', '$key', $object],
['content-length-range', 0, 1048576000]
]
];
$policyJson = json_encode($policy);
$policyBase64 = base64_encode($policyJson);
$signature = base64_encode(hash_hmac('sha1', $policyBase64, $accessKeySecret, true));
return [
'accessid' => $accessKeyId,
'host' => "https://{$host}",
'policy' => $policyBase64,
'signature' => $signature,
'expire' => $expireTime,
'key' => $object,
'callback' => '' // 可选:回调URL
];
}
腾讯云COS 直传签名
使用临时密钥(推荐)
<?php
require_once 'vendor/autoload.php';
use Qcloud\Cos\Client;
$secretId = 'your-secret-id';
$secretKey = 'your-secret-key';
$region = 'ap-guangzhou';
$bucket = 'example-1250000000';
// 获取临时密钥
try {
$cosClient = new Client([
'region' => $region,
'schema' => 'https',
'credentials' => [
'secretId' => $secretId,
'secretKey' => $secretKey
]
]);
// 申请临时密钥(需额外安装Qcloud/Cos模块)
$result = $cosClient->getObjectUrl($bucket, 'test.txt', '+1 hour');
// 或者手动生成临时密钥
$tempKeys = [
'TmpSecretId' => 'your-temp-secret-id',
'TmpSecretKey' => 'your-temp-secret-key',
'Token' => 'your-temp-token',
'ExpiredTime' => time() + 3600,
'StartTime' => time(),
'Region' => $region,
'Bucket' => $bucket
];
echo json_encode($tempKeys);
} catch (Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
}
简单上传签名
<?php
function getCosUploadSignature($bucket, $region, $expiration = 3600) {
$secretId = 'your-secret-id';
$secretKey = 'your-secret-key';
$currentTime = time();
$keyTime = "{$currentTime};{$currentTime}+{$expiration}";
$signKey = hash_hmac('sha1', $keyTime, $secretKey);
// 构建签名
$httpMethod = 'post';
$uri = '/';
$headers = "host={$bucket}.cos.{$region}.myqcloud.com";
$params = '';
$stringToSign = "{$httpMethod}\n{$uri}\n{$params}\n{$headers}\n";
$signature = hash_hmac('sha1', $stringToSign, $signKey);
return [
'secretId' => $secretId,
'signature' => $signature,
'keyTime' => $keyTime,
'bucket' => $bucket,
'region' => $region
];
}
AWS S3 直传签名
<?php
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Credentials\Credentials;
// 配置
$region = 'us-east-1';
$bucket = 'your-bucket';
$awsKey = 'your-aws-access-key';
$awsSecret = 'your-aws-secret-key';
// 创建S3客户端
$s3Client = new S3Client([
'version' => 'latest',
'region' => $region,
'credentials' => new Credentials($awsKey, $awsSecret)
]);
// 生成预签名上传URL
try {
$command = $s3Client->getCommand('PutObject', [
'Bucket' => $bucket,
'Key' => 'uploads/' . uniqid() . '.jpg',
'ACL' => 'public-read',
'ContentType' => 'image/jpeg'
]);
$presignedUrl = $s3Client->createPresignedRequest($command, '+1 hour');
$url = (string) $presignedUrl->getUri();
echo json_encode(['uploadUrl' => $url]);
} catch (Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
}
通用直传签名(自建服务)
<?php
class DirectUploadSigner {
private $secretKey;
public function __construct($secretKey) {
$this->secretKey = $secretKey;
}
public function generateSignedUrl($bucket, $object, $expiration = 3600) {
$expireTime = time() + $expiration;
$data = "{$bucket}|{$object}|{$expireTime}";
$signature = hash_hmac('sha256', $data, $this->secretKey);
return [
'url' => "https://your-storage.com/{$bucket}/{$object}",
'expires' => $expireTime,
'signature' => $signature,
'key' => $object,
'token' => base64_encode("{$signature}:{$expireTime}:{$bucket}:{$object}")
];
}
public function verifySignedToken($token) {
$decoded = base64_decode($token);
$parts = explode(':', $decoded);
if (count($parts) !== 4) {
return false;
}
list($signature, $expireTime, $bucket, $object) = $parts;
// 检查是否过期
if (time() > $expireTime) {
return false;
}
// 验证签名
$data = "{$bucket}|{$object}|{$expireTime}";
$expectedSignature = hash_hmac('sha256', $data, $this->secretKey);
return hash_equals($expectedSignature, $signature);
}
}
// 使用示例
$signer = new DirectUploadSigner('your-secret-key-here');
$signedData = $signer->generateSignedUrl('my-bucket', 'photos/avatar.jpg', 3600);
echo json_encode($signedData);
最佳实践建议
-
安全考虑:
- 永远不要在客户端暴露长期密钥
- 使用STS/RAM角色获取临时凭证
- 设置合理的过期时间(通常15分钟-1小时)
- 限制上传文件类型和大小
-
性能优化:
- 缓存临时凭证到会话或内存
- 预生成多个签名减少请求
-
错误处理:
- 添加重试机制
- 完善的日志记录
- 前端签名验证
-
权限控制:
- 最小权限原则
- 每个用户/请求独立签名
- 后端验证上传完成的文件
选择哪种方案取决于你的云服务提供商和具体需求,推荐使用云服务商的STS临时凭证方案,安全性更高。