如何使用Node.js下载OneDrive共享文件?Azure认证尝试失败
解决Node.js下载OneDrive共享文件的方案
核心问题说明
你用的客户端凭证模式(Client Credentials Flow)是服务到服务的认证逻辑,无法访问绑定个人账号权限的OneDrive共享文件——这类文件的访问权限基于你的个人身份,而非Azure应用本身的身份。OAuth2认证失败大概率是选错了授权流程,应该改用**授权码授权流程(Authorization Code Flow)**来模拟个人用户身份获取权限。
步骤1:调整Azure应用配置
- 在Azure门户的应用注册页面,进入「身份验证」模块,添加Web应用/单页应用类型的重定向URI(示例:
http://localhost:3000/redirect) - 切换到「API权限」,添加
Files.Read.All、Sites.Read.All这两个委托权限(注意不是应用权限),完成后点击「授予管理员同意」(针对租户账号)
步骤2:用@azure/msal-node实现授权码流程
以下是完整可运行的代码示例,先启动本地服务引导用户完成授权,再通过授权码获取令牌,最后调用Graph API批量下载文件:
const msal = require('@azure/msal-node'); const axios = require('axios'); const fs = require('fs'); const http = require('http'); const path = require('path'); // MSAL基础配置 const config = { auth: { clientId: '你的Azure应用客户端ID', authority: 'https://login.microsoftonline.com/你的租户ID', clientSecret: '你的Azure应用密钥' } }; const pca = new msal.PublicClientApplication(config); const REDIRECT_URI = 'http://localhost:3000/redirect'; const SCOPES = ['Files.Read.All', 'Sites.Read.All', 'offline_access']; const DOWNLOAD_DIR = './onedrive_downloads'; // 创建本地下载目录 if (!fs.existsSync(DOWNLOAD_DIR)) { fs.mkdirSync(DOWNLOAD_DIR); } // 启动本地HTTP服务处理授权回调 const server = http.createServer(async (req, res) => { // 处理授权回调 if (req.url.startsWith('/redirect')) { const urlParams = new URL(req.url, `http://${req.headers.host}`).searchParams; const authCode = urlParams.get('code'); if (!authCode) { res.end('未获取到授权码,请重新尝试'); return; } try { // 用授权码交换访问令牌 const tokenResult = await pca.acquireTokenByCode({ code: authCode, scopes: SCOPES, redirectUri: REDIRECT_URI }); const accessToken = tokenResult.accessToken; // 替换为你的共享文件夹ID const sharedFolderId = '共享文件夹的ID'; // 获取文件夹下所有文件列表 const filesRes = await axios.get( `https://graph.microsoft.com/v1.0/me/drive/items/${sharedFolderId}/children`, { headers: { Authorization: `Bearer ${accessToken}` } } ); // 批量下载文件 for (const item of filesRes.data.value) { if (item.file) { const fileStream = await axios.get( `https://graph.microsoft.com/v1.0/me/drive/items/${item.id}/content`, { headers: { Authorization: `Bearer ${accessToken}` }, responseType: 'stream' } ); const savePath = path.join(DOWNLOAD_DIR, item.name); fileStream.data.pipe(fs.createWriteStream(savePath)); console.log(`已完成下载:${item.name}`); } } res.end('所有文件下载完成,可关闭此页面'); server.close(); } catch (err) { console.error('操作失败:', err.message); res.end(`出错了:${err.message}`); } } else { // 引导用户跳转至微软授权页面 const authUrl = await pca.getAuthCodeUrl({ scopes: SCOPES, redirectUri: REDIRECT_URI }); res.writeHead(302, { Location: authUrl }); res.end(); } }); server.listen(3000, () => { console.log('请访问 http://localhost:3000 完成授权登录'); });
步骤3:获取共享文件夹ID的方法
如果不知道共享文件夹的ID,可通过两种方式获取:
- 打开共享链接,在浏览器控制台执行
window.location.pathname,提取路径中的资源ID; - 调用Graph API搜索接口:发送GET请求到
https://graph.microsoft.com/v1.0/me/drive/search(q='共享文件夹名称'),在返回结果中找到对应文件夹的id字段。
关键注意事项
- 必须使用委托权限,应用权限无法访问用户个人OneDrive的共享内容;
- 授权码流程需要用户手动登录一次,获取到的refresh token可用于后续刷新访问令牌,无需重复登录;
- 确保本地下载目录已创建,否则会出现文件写入失败的错误。
内容的提问来源于stack exchange,提问作者Sajib Hossain
相关产品推荐
相关产品推荐

