基于REST API在PHP中生成Azure Blob Storage的SAS令牌
Laravel后端生成Azure Blob Storage Valet Key模式SAS令牌(原生REST实现)
核心逻辑说明
Valet Key模式的关键是后端生成最小权限、短期有效的SAS令牌,仅允许前端完成指定操作(如上传到特定容器)。由于PHP SDK停用,需手动实现Azure SAS的签名算法——核心是按照Azure规范构造待签名字符串,再通过HMAC-SHA256生成签名。
步骤1:准备必要参数
确保你已获取以下信息:
- Azure存储账户名(
$accountName) - 存储账户访问密钥(
$accountKey,在Azure门户存储账户的"访问密钥"中获取) - 目标容器名(
$containerName) - 所需权限:上传文件只需
w(写权限),如需列出容器文件可加l,按需组合 - SAS过期时间:建议设置较短有效期(如15分钟),降低泄露风险
步骤2:Laravel后端生成SAS的代码实现
在Laravel控制器中添加生成SAS的方法,通过Inertia将SAS传递给前端:
<?php namespace App\Http\Controllers; use Inertia\Inertia; class AzureBlobController extends Controller { public function getUploadSas() { $accountName = env('AZURE_STORAGE_ACCOUNT'); $accountKey = env('AZURE_STORAGE_KEY'); $containerName = 'your-container-name'; $permissions = 'w'; // 仅写权限,适配上传场景 $expiryMinutes = 15; // SAS有效期15分钟 // 构造UTC时间参数(ISO 8601格式) $startTime = gmdate('Y-m-d\TH:i:s\Z'); $expiryTime = gmdate('Y-m-d\TH:i:s\Z', time() + ($expiryMinutes * 60)); // 规范化资源路径:/blob/账户名/容器名 $canonicalResource = "/blob/{$accountName}/{$containerName}"; // 待签名字符串(严格遵循Azure指定顺序,空参数留空) $stringToSign = implode("\n", [ $permissions, $startTime, $expiryTime, $canonicalResource, '', // 规范化头部(可选,此处留空) '', // 签名头部(可选,此处留空) '', // 协议(可选,此处留空) '2022-11-02' // SAS版本,建议使用最新稳定版 ]); // 生成HMAC-SHA256签名 $decodedKey = base64_decode($accountKey); $signature = hash_hmac('sha256', $stringToSign, $decodedKey, true); $encodedSignature = urlencode(base64_encode($signature)); // 拼接完整SAS令牌 $sasToken = http_build_query([ 'sv' => '2022-11-02', 'st' => $startTime, 'se' => $expiryTime, 'sr' => 'c', // 资源类型:c=容器,b=单个Blob 'sp' => $permissions, 'sig' => $encodedSignature ]); // 通过Inertia传递SAS令牌给前端 return Inertia::render('UploadPage', [ 'azureSasToken' => $sasToken, 'storageAccount' => $accountName, 'containerName' => $containerName ]); } }
步骤3:前端(React/Inertia)上传文件示例
在React组件中,使用获取到的SAS令牌直接向Azure Blob Storage发起上传请求:
import { useState } from 'react'; import { usePage } from '@inertiajs/react'; export default function UploadPage() { const { azureSasToken, storageAccount, containerName } = usePage().props; const [selectedFile, setSelectedFile] = useState(null); const handleFileChange = (e) => { setSelectedFile(e.target.files[0]); }; const handleUpload = async () => { if (!selectedFile) return; // 构造Blob上传URL:https://账户名.blob.core.windows.net/容器名/文件名?SAS令牌 const blobName = `uploaded-${Date.now()}-${selectedFile.name}`; const uploadUrl = `https://${storageAccount}.blob.core.windows.net/${containerName}/${blobName}?${azureSasToken}`; try { const response = await fetch(uploadUrl, { method: 'PUT', body: selectedFile, headers: { 'Content-Type': selectedFile.type } }); if (response.ok) { alert('文件上传成功'); // 可在此处理后续逻辑,如将Blob URL保存到后端数据库 } else { alert('上传失败,请重试'); } } catch (error) { console.error('上传错误:', error); alert('上传出错,请检查网络连接'); } }; return ( <div> <input type="file" onChange={handleFileChange} /> <button onClick={handleUpload} disabled={!selectedFile}> 上传到Azure Blob </button> </div> ); }
关键注意事项
- 权限最小化:仅授予必要权限(如上传只用
w),避免使用rwd全权限,降低令牌泄露风险 - 短期有效期:设置15-30分钟的过期时间,即使令牌泄露也不会被长期滥用
- HTTPS强制:确保前端上传使用HTTPS,防止SAS令牌在传输过程中被窃取
- SAS版本:使用Azure支持的最新SAS版本(如
2022-11-02),避免版本兼容问题
内容的提问来源于stack exchange,提问作者LucaSpeedStack
相关产品推荐
相关产品推荐

