如何授权Azure B2C用户读取Azure Storage Blob及生成用户委托SAS令牌
方案一:用户委派SAS令牌实现(推荐通过后端API代理)
由于SPA直接在前端生成用户委派SAS会暴露敏感操作逻辑,建议通过Next.js的API路由作为中间层完成,步骤如下:
1. 获取用户的Azure Storage访问令牌
用户通过NextAuth登录后,需获取针对Azure Blob Storage的访问令牌(而非ID令牌):
- 在
[...nextauth].js的AAD B2C Provider配置中,添加存储服务的权限scope:
providers: [ AzureADB2CProvider({ clientId: process.env.AZURE_AD_B2C_CLIENT_ID, clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET, tenantId: process.env.AZURE_AD_B2C_TENANT_ID, scope: 'openid offline_access https://storage.azure.com/user_impersonation', // 其他B2C相关配置 }) ]
- 登录后,可通过
useSession钩子或API路由的req.session获取用户的accessToken,需确认该令牌的受众为Azure Storage服务。
2. 后端API路由生成用户委派密钥与SAS
创建Next.js API路由(如pages/api/generate-sas.js),完成以下操作:
- 验证用户会话(通过
getServerSession确保只有已登录用户可访问) - 使用用户的访问令牌获取用户委派密钥
- 基于密钥生成用户委派SAS令牌
示例代码:
import { BlobServiceClient, generateUserDelegationSAS } from '@azure/storage-blob'; import { getServerSession } from 'next-auth/next'; import { authOptions } from './auth/[...nextauth]'; export default async function handler(req, res) { const session = await getServerSession(req, res, authOptions); if (!session) return res.status(401).json({ error: 'Unauthorized' }); const { containerName, blobName } = req.body; const accessToken = session.user.accessToken; // 初始化Blob服务客户端 const blobServiceClient = new BlobServiceClient( `https://${process.env.STORAGE_ACCOUNT_NAME}.blob.core.windows.net`, new TokenCredential(accessToken) ); // 获取用户委派密钥(有效期1小时) const userDelegationKey = await blobServiceClient.getUserDelegationKey( new Date(), new Date(Date.now() + 3600 * 1000) ); // 生成只读权限的用户委派SAS const sasToken = generateUserDelegationSAS({ containerName, blobName, userDelegationKey, startsOn: new Date(), expiresOn: new Date(Date.now() + 3600 * 1000), permissions: 'r', protocol: 'https' }); res.status(200).json({ sasToken }); }
3. 前端使用SAS访问Blob
前端拿到SAS令牌后,拼接成Blob的完整访问URL:https://{storage-account-name}.blob.core.windows.net/{container}/{blob}?{sasToken}
直接请求该URL即可读取文件,Azure Storage会自动验证SAS对应的RBAC权限。
方案二:替代方案——后端代理Blob请求(更安全)
若用户委派SAS流程过于繁琐,可采用后端代理的方式,完全屏蔽存储资源的直接访问:
- 前端请求Next.js API路由,传入目标Blob的容器名和文件名
- API路由验证用户会话后,用用户的访问令牌直接访问Blob并返回内容
示例代码:
import { BlobServiceClient } from '@azure/storage-blob'; import { getServerSession } from 'next-auth/next'; import { authOptions } from './auth/[...nextauth]'; export default async function handler(req, res) { const session = await getServerSession(req, res, authOptions); if (!session) return res.status(401).json({ error: 'Unauthorized' }); const { containerName, blobName } = req.query; const accessToken = session.user.accessToken; const blobServiceClient = new BlobServiceClient( `https://${process.env.STORAGE_ACCOUNT_NAME}.blob.core.windows.net`, new TokenCredential(accessToken) ); const containerClient = blobServiceClient.getContainerClient(containerName); const blobClient = containerClient.getBlobClient(blobName); // 获取Blob流并返回给前端 const downloadResponse = await blobClient.download(); res.setHeader('Content-Type', downloadResponse.contentType); downloadResponse.readableStreamBody.pipe(res); }
这种方式下,Azure Storage会直接通过用户的访问令牌验证RBAC权限,无需手动处理SAS逻辑,且存储资源的URL不会暴露给前端。
关键注意事项
- RBAC权限配置:确保用户所属的AAD组被分配了对应的存储角色,如
Storage Blob Data Reader(只读权限),这是所有授权逻辑的基础。 - 令牌刷新:用户的访问令牌存在有效期,NextAuth通常会自动处理刷新令牌流程,需确保配置正确。
- 安全约束:所有涉及令牌、密钥的操作必须在后端完成,绝对不能在前端处理敏感逻辑,避免信息泄露。
内容的提问来源于stack exchange,提问作者magnetarneo
相关产品推荐
相关产品推荐

