You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Azure应用权限从SharePoint获取图片生成PDF时仍遭遇401未授权错误

使用Azure应用权限从SharePoint获取图片生成PDF时仍遭遇401未授权错误

我正尝试通过URL获取存储在SharePoint中的图片,并将其嵌入到用JavaScript生成的PDF里。在浏览器中(已登录微软账号)获取图片是正常的,但导出PDF时图片无法显示。

为解决这个问题,我尝试用Azure应用进行身份验证,给应用授予了Sites.Read.AllFiles.Read.All权限,但获取图片时还是收到401 Unauthorized错误。

以下是我目前尝试过的方法:

1. 浏览器中直接获取图片(可行)

fetch('https://<sharepoint-site>/<image-url>')
  .then(response => response.blob())
  .then(blob => {
    // 处理图片
  });

2. 使用Azure应用身份验证(返回401失败)

const token = await getAccessToken(); // 通过Azure AD获取令牌的函数
fetch('https://<sharepoint-site>/<image-url>', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
})
  .then(response => {
    if (!response.ok) throw new Error('Network response was not ok');
    return response.blob();
  })
  .then(blob => {
    // 处理图片
  })
  .catch(error => console.error('Error fetching image:', error));

3. Azure应用权限配置

  • Sites.Read.All
  • Files.Read.All

尽管配置了这些权限,我还是遇到了401 Unauthorized错误。是不是在身份验证流程或者权限设置中遗漏了什么?

补充背景

  • 我使用Microsoft Graph API进行身份验证。
  • 登录浏览器账号后可以正常访问SharePoint站点和图片。
  • 我使用的PDF生成库是html2pdf

非常感谢任何帮助或指导!


可能的问题排查与解决方案

看起来你已经做了基础的权限配置,但401错误通常和令牌的受众、权限范围或者请求URL的格式有关,我来帮你逐一排查:

1. 检查令牌的受众和权限范围

首先,确保你获取的访问令牌是针对SharePoint/Graph API的,而不是其他资源。可以用JWT解析工具解码令牌,查看这两个关键字段:

  • aud:应该是https://<你的SharePoint域名>.sharepoint.com或者https://graph.microsoft.com(如果用Graph API路径访问的话)
  • roles:确认包含Sites.Read.AllFiles.Read.All(应用权限会出现在roles字段,委派权限在scp字段)

如果令牌受众不对,比如是针对Azure管理API的,那肯定无法访问SharePoint资源。调整getAccessToken函数中的resourcescope参数,比如请求https://<sharepoint-site>.sharepoint.com/.default作为范围。

2. 改用Microsoft Graph API的正确路径获取图片

直接通过SharePoint站点URL访问文件时,有些场景下Bearer令牌的验证逻辑和Graph API不同。建议改用Microsoft Graph的文件端点来获取图片,这样更符合Azure AD的验证流程:

// 假设图片的Site ID、Drive ID、Item ID已知,通过Graph API路径获取
const graphUrl = `https://graph.microsoft.com/v1.0/sites/<site-id>/drives/<drive-id>/items/<item-id>/content`;
const token = await getAccessToken(); // 确保令牌的aud是https://graph.microsoft.com

fetch(graphUrl, {
  headers: { 'Authorization': `Bearer ${token}` }
})
.then(response => response.blob())
.then(blob => {
  // 处理图片后嵌入PDF
});

如果不知道Site/Drive/Item ID,可以先调用Graph API的GET /sites/<sharepoint-site-url>来获取站点信息,再逐层找到文件的ID。

3. 确认应用权限已完成管理员同意

你在Azure门户中添加的应用权限,需要全局管理员或SharePoint管理员点击“授予管理员同意”,否则权限只是“待同意”状态,不会生效。检查权限列表中是否有“已授予”的标记。

4. 检查SharePoint文件的权限继承

即使应用有Files.Read.All权限,如果该图片所在的文档库或文件夹设置了权限继承中断,并且没有给Azure应用的服务主体(企业应用)分配读取权限,也会返回401。可以在SharePoint中给文档库添加应用服务主体的读取权限:

  1. 打开SharePoint文档库的“设置”→“库权限”
  2. 点击“授予权限”,搜索你的Azure应用名称(服务主体名称)
  3. 分配“读取”权限

5. 针对html2pdf的特殊处理

html2pdf在处理外部资源时,可能会忽略请求头中的Authorization信息。如果是在前端生成PDF,你可以先把图片转换成Data URL,再嵌入到HTML中,这样html2pdf就能直接读取:

const token = await getAccessToken();
fetch('https://<sharepoint-site>/<image-url>', {
  headers: { 'Authorization': `Bearer ${token}` }
})
.then(response => response.blob())
.then(blob => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result); // 得到Data URL
    reader.onerror = reject;
    reader.readAsDataURL(blob);
  });
})
.then(dataUrl => {
  // 将dataUrl插入到HTML的<img src="...">中,再用html2pdf生成PDF
  document.getElementById('pdf-image').src = dataUrl;
  html2pdf().from(document.getElementById('pdf-container')).save();
});

6. 检查令牌的过期时间和签名

有时候令牌过期或者签名验证失败也会导致401,确保getAccessToken函数在令牌过期时能自动刷新,并且使用的是正确的租户ID和应用密钥/证书。

如果尝试以上方法后还是有问题,建议捕获并打印response.headers中的WWW-Authenticate字段,这个字段会给出更具体的401原因(比如令牌无效、权限不足等),能帮助进一步定位问题。


备注:内容来源于stack exchange,提问作者Mohamed Yassine Baananou

火山引擎 最新活动