【问题标题】:Uploading a large attachment using Microsoft Graph got invalid_token error使用 Microsoft Graph 上传大型附件时出现 invalid_token 错误
【发布时间】:2020-09-17 08:09:29
【问题描述】:

我正在尝试使用 Microsoft Graph Java SDK 2.10 将大 (> 4mb) 附件上传到 Office 365 中的现有邮件。我正在遵循这些说明:https://docs.microsoft.com/en-us/graph/outlook-large-attachments?tabs=java

我已经成功创建了上传会话,并获得了一个与文档中的示例类似的 uploadUrl 值。然后我使用 ChunkedUploadProvider 开始对这个 url 进行 PUT。

        // Create an upload session
        UploadSession uploadSession = client.me()
                .messages(messageId).attachments()
                .createUploadSession(attachmentItem)
                .buildRequest()
                .post();

        ChunkedUploadProvider<AttachmentItem> chunkedUploadProvider =
                new ChunkedUploadProvider<AttachmentItem>
                        (uploadSession, client, fileStream, attachmentItem.size, AttachmentItem.class);

        // Config parameter is an array of integers
        // customConfig[0] indicates the max slice size
        // Max slice size must be a multiple of 320 KiB
        int[] customConfig = { 12 * 320 * 1024 }; // still < 4MB as API recommended

        // Do the upload
        try {
            chunkedUploadProvider.upload(callback, customConfig);
        } catch (Exception e) {
            log.error("Upload attachment file name {} for message id {}", fileAttachment.name, messageId, e);
        }

我的问题是我得到 http 401 (Unauthorized) 作为响应:

{
  "error": {
    "code": "InvalidMsaTicket",
    "message": "ErrorCode: \u0027PP_E_RPS_CERT_NOT_FOUND\u0027. Message: \u0027 Internal error: spRPSTicket-\u003eProcessToken failed. Failed to call CRPSDataCryptImpl::UnpackData: Internal error: Failed to decrypt data. :Failed to get session key. RecipientId\u003d293577. spCache-\u003eGetCacheItem returns error.:Cert Name: (null). SKI: 3bd72187c709b1c40b994f8b496a5b9ebd2f9b0c...\u0027",
    "innerError": {
      "requestId": "7276a164-9c13-41cc-b46a-4a86303017a6",
      "date": "2020-09-17T04:55:15"
    }
  }
}

我注意到创建上传会话的请求是:

https://graph.microsoft.com/v1.0/me/messages/AQMkADAwATM3ZmYAZS0xNWU2LTc4N1agAAAA==/attachments

uploadUrl 是:

https://outlook.office.com/api/v2.0/Users('00037ffe-15e6-787e-0000-00000')/Messages('AQMkADAwATM3ZmYAZS0xNVtUUgAAAA==')/AttachmentSessions('AQMkADAwwAAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNIdDRobk9JQnpndlU5MD0iL

这是一个不同的 API(Graph 与 Outlook)。

我已经添加了邮件 read.write 范围,这允许我创建一个

任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 我在stackoverflow.com/questions/59726497/… 看到了一个类似的问题,它得到了@JeffMcKay 提出的不同的错误消息(“观众声明值对当前资源无效......”)。我不确定他是如何解决他的问题的。
  • 您是如何请求令牌的?您需要为您的受众设置范围,并且您的受众必须是您的令牌接收者。
  • 检查你的'aud',确保是你要调用的api,以及401的原因你可能使用了错误的token或者你使用了不属于的token api调用api。
  • @CarlZhao uploadUrl 是在 createUploadSession API 的响应中生成并返回的。 uploadUrl 中的 authtoken 参数有 'aud' 是“outlook.office.com/api”,我认为它是正确的。从“login.microsoftonline.com/common/oauth2/v2.0/token”API 获取访问令牌作为用户同意时,我已将“outlook.office.com/Mail.ReadWrite”放入范围,但没有帮助。是否可以获得 Graph 和 Outlook 范围组合的访问令牌,例如:Mail.ReadWrite 和 outlook.office.com/Mail.ReadWrite,这两个 API 都适用?

标签: microsoft-graph-api outlook-api


【解决方案1】:

我的错。请求不应包含授权标头:

不要指定授权请求标头。 PUT 查询使用来自 uploadUrl 属性的预认证 URL,允许访问 https://outlook.office.com 域。

删除了授权标头,请求正常工作。

【讨论】:

  • 您是如何从图形客户端中删除授权标头的?我面临与 chunkedUploadProvider.upload 相同的问题。谢谢
  • @timp 只是不要在 PUT 查询中指定它。
【解决方案2】:

只需对该 URL 使用普通 cURL PUT 请求,它就会起作用...在 PHP 中,它会是这样的(使用 php-curl-class/php-curl-class 和 microsoft/microsoft-graph 作曲家库):

function uploadLargeFileData(Graph $graph, string $messageId, string $fileName, string $fileContentType, string $fileData) : bool {

  $fileSize = strlen($fileData);
  // create upload session
  $attachmentItem = (new AttachmentItem())
    ->setAttachmentType('file')
    ->setName($fileName)
    ->setSize($fileSize)
    ->setContentType($fileContentType);

  /** @var UploadSession $uploadSession */
  try {
    $uploadSession = $graph->createRequest('POST', "/me/messages/{$messageId}/attachments/createUploadSession")
      ->addHeaders(['Content-Type' => 'application/json'])
      ->attachBody(['AttachmentItem' => $attachmentItem])
      ->setReturnType(UploadSession::class)
      ->execute();
  }
  catch (GraphException $e) {
    return false;
  }

  $fileData = str_split($fileData, self::LargeFileChunkSize);
  $fileDataCount = count($fileData);

  foreach ($fileData as $chunkIndex => $chunkData) {
    $chunkSize = strlen($chunkData);
    $rangeStart = $chunkIndex * self::LargeFileChunkSize;
    $rangeEnd = $rangeStart + $chunkSize - 1;

    try {
      // we need to use this plain access, because calling the API via the Graph provider leads to strange error of invalid audience
      $curl = new Curl();
      $curl->setHeaders([
          'Content-Length' => $chunkSize,
          'Content-Range' => "bytes {$rangeStart}-{$rangeEnd}/{$fileSize}",
          'Content-Type' => 'application/octet-stream',
        ]);

      $curl->put($uploadSession->getUploadUrl(), $chunkData);

      if ($chunkIndex < $fileDataCount - 1 && $curl->httpStatusCode != 200) { // partial are responding with 200
        return false;
      }
      elseif ($chunkIndex == $fileDataCount - 1 && $curl->httpStatusCode != 201) { // last response should have code 201
        return false;
      }
    }
    catch (\Exception $e) {
      return false;
    }
  }

  return true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-07
    • 2015-03-08
    • 2020-07-31
    相关资源
    最近更新 更多