我正在尝试使用 azure 服务构建一个 nextjs 应用程序,该服务应仅可供我的 microsoft 租户中的用户使用。我遇到的最大问题是数据库连接只能在静态 Web 应用程序模拟器 (localhost:4280) 上工作,而从存储帐户容器中提取数据只能在 localhost:3000 上工作。
当前资源
我做的第一件事是设置静态 Web 应用程序并将其链接到生成 CI/CD 工作流程的存储库。接下来,我尝试解决数据库问题。我创建了一个
staticwebapp.database.config.json
文件。swa start http://localhost:3000 --run 'npm run dev' --data-api-location swa-db-connection
启动应用程序时,我可以很好地看到从 SQL 数据库中提取的数据。
存储帐户才是真正混乱的地方。微软表示:
“要在 JavaScript 应用程序中使用 DefaultAzureCredential,请将 @azure/identity 包添加到您的应用程序中。”
// connect-with-default-azure-credential.js
import { BlobServiceClient } from '@azure/storage-blob';
import { DefaultAzureCredential } from '@azure/identity';
import 'dotenv/config'
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
if (!accountName) throw Error('Azure Storage accountName not found');
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.windows.net`,
new DefaultAzureCredential()
);
尝试后,我发现
DefaultAzureCredential()
在浏览器中不起作用。您必须使用 InteractiveBrowserCredential
,它接受 clientId 和tenantId。我最终能够完成这项工作,但是当将部分移动到 NextJS API 路由以保护环境变量时,这就是我遇到的下一个问题。
当我尝试从模拟器 (localhost:4280) 获取 NextJS API 路由时,它在终端中给出一个块,指出“检测到功能请求,但未找到端点配置。请使用 --api-location 选项来配置函数端点。”如果我使用 localhost:3000,这些 API 路由调用就可以正常工作。
我的下一个问题是,当我使用 interactivebrowsercredential 时,会出现弹出窗口,然后在我的终端中,我收到一条错误消息,指出
"Token issued for the Single-Page Application client-type may only be redeemed via cross-origin requests"
。
我希望实现的是实现 msal2 以预先对用户进行身份验证,然后尝试以无缝方式将该身份验证用于这些其他 Azure 服务。
我知道我在这里遇到了多个不同的问题,但任何朝正确方向的推动都会有很大帮助。我花了几天时间阅读文档并寻找资源,但我觉得我有点陷入困境。
提前谢谢您!
此 Git issue 涉及在 Identity 中使用交互式浏览器凭据进行浏览器身份验证。如果提到默认 Azure 凭据,它会根据环境选择凭据,如Stack Overflow中所述。
使用
Azure.Identity
连接到 Azure Blob 存储的代码取自此 reference。
import React, { useEffect, useState } from 'react';
import { InteractiveBrowserCredential } from '@azure/identity';
import { BlobServiceClient, BlobItem } from '@azure/storage-blob';
interface BlobViewProps {}
const BlobView: React.FC<BlobViewProps> = () => {
const [blobsWeFound, setBlobsWeFound] = useState<BlobItem[]>([]);
const [containerUrl, setContainerUrl] = useState<string>('');
useEffect(() => {
const signInOptions = {
clientId: 'clientId', // Your application client ID
tenantId: 'tenantId', // Your Azure AD tenant ID
};
const fetchBlobData = async () => {
try {
const blobStorageClient = new BlobServiceClient(
'https://<your-storage-account-name>.blob.core.windows.net/',
new InteractiveBrowserCredential(signInOptions)
);
const containerClient = blobStorageClient.getContainerClient('private');
const blobList: BlobItem[] = [];
for await (const blob of containerClient.listBlobsFlat()) {
blobList.push(blob);
}
setBlobsWeFound(blobList);
setContainerUrl(containerClient.url);
} catch (error) {
console.error('Error fetching blob data:', error);
}
};
fetchBlobData();
}, []);
return (
<div>
<table>
<thead>
<tr>
<th>blob name</th>
<th>blob size</th>
<th>download url</th>
</tr>
</thead>
<tbody>
{blobsWeFound.map((blob, index) => (
<tr key={index}>
<td>{blob.name}</td>
<td>{blob.properties?.contentLength}</td>
<td>
<img src={`${containerUrl}${blob.name}`} alt={blob.name} />
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default BlobView;
Next.js 文档应包含有关为 API 路由配置 CORS(跨源资源共享)的部分。这将启用应用程序前端 (localhost:4280) 和 API 路由 (localhost:3000) 之间的通信。