PHP网站调用Microsoft Graph API上传OneDrive遭403拒绝的排查方案
我有一个供客户查看发票并上传设计资产的网站,想用PHP表单把文件传到OneDrive,不存储在Web服务器上。已经在Microsoft Azure创建应用,配置了Application (client) ID、Directory (tenant) ID等信息,使用客户端密钥及账号密码获取访问令牌,相关代码如下:
if (isset($_FILES['uploads'])) { $guzzle = new \GuzzleHttp\Client(); $tenantId = 'xxxxxx'; $clientId = 'xxxxxx'; $clientSecret = 'xxxxxx'; $url = 'https://login.microsoftonline.com/' . $tenantId . '/oauth2/token'; $user_token = json_decode($guzzle->post($url, [ 'form_params' => [ 'client_id' => $clientId, 'client_secret' => $clientSecret, 'resource' => 'https://graph.microsoft.com/', 'grant_type' => 'password', 'username' => 'xxxxxx@companydomain.com', 'password' => 'xxxxxx' ], ])->getBody()->getContents()); $user_accessToken = $user_token->access_token; $graph = new Graph(); $graph->setAccessToken($user_accessToken); foreach ($_FILES['uploads']['name'] as $key => $name) { try { $graph->createRequest( "PUT", "/drive/root:/Documents/".$_FILES['uploads']['name'][$key].":/content" )->upload( $_FILES['uploads']['tmp_name'][$key] ); } catch (Exception $e) { var_dump($e); } } }
尝试上传文件时抛出异常:
Client error:
PUT https://graph.microsoft.com/v1.0/drive/root:/Documents/Screen%20Shot%202022-10-30%20at%204.03.44%20PM.png:/contentresulted in a403 Forbiddenresponse
Azure API权限中已授予Files.Read.All、Files.ReadWrite.All和User.Read权限,但检查访问令牌时仅看到"scp": "User.Read",令牌未获取到正确权限,请问如何解决?
1. 确认权限已完成管理员同意
Azure中添加的Files.Read.All、Files.ReadWrite.All这类高权限,必须点击API权限页面顶部的授予管理员同意按钮。未完成此操作的话,即使配置了权限,令牌也不会包含这些权限。
2. 在令牌请求中明确指定权限范围
使用password授权类型时,需要在请求的form_params里添加scope参数,明确声明所需权限:
'form_params' => [ 'client_id' => $clientId, 'client_secret' => $clientSecret, 'resource' => 'https://graph.microsoft.com/', 'grant_type' => 'password', 'username' => 'xxxxxx@companydomain.com', 'password' => 'xxxxxx', 'scope' => 'Files.ReadWrite.All User.Read' // 新增该行指定权限范围 ]
注:resource是旧版端点参数,搭配scope可确保请求的权限被纳入令牌。
3. 检查权限类型是否匹配授权模式
当前使用的是password授权(委派模式,以用户身份操作),需确认添加的是委派权限而非应用权限:
- 上传到用户个人OneDrive,选择委派权限的
Files.ReadWrite.All; - 上传到应用专属存储(如SharePoint文档库),才用应用权限。
4. 重新验证令牌内容
重新获取令牌后,再次检查scp字段是否包含Files.ReadWrite.All。若仍未出现,可尝试重新生成客户端密钥,或清除应用缓存后再次请求令牌。
5. 确认OneDrive目标路径权限
即使令牌权限正确,也要确保目标文件夹/Documents/对该用户有写入权限,比如企业OneDrive可能存在文件夹权限限制,需验证用户可访问并写入该路径。
内容的提问来源于stack exchange,提问作者Sam Nabi

