java Outlook OAuth2访问邮件

txu3uszq  于 2023-01-01  发布在  Java
关注(0)|答案(2)|浏览(316)

我正在关注这个帖子:Outlook RestGettingStarted。我正在尝试从Java应用程序获取AccessToken和RefreshToken。当我发出授权码请求时,出现以下错误:
很抱歉,您登录时遇到问题。我们收到了一个错误请求。
其他技术信息:相关性ID:版本838d66 - 5f2e-4cfb-9223-a29082ecb26f时间戳:2015年8月20日10:20:09澳大利亚航空航天学会90011:不支持"resource"请求参数。

    • 注:**URL格式与文档一致。

所以,我从我的代码中删除了"资源"查询参数。并在浏览器中重定向授权URL。在用户同意我得到了授权代码。使用此代码我得到了AccessToken。但当我尝试与Outlook IMAP服务器连接时失败。Java参考链接了解详情:Java OAuth2但它给我错误:
[验证失败] OAuth验证失败。

    • 注:**我添加了正确的范围和用户电子邮件。

然后使用获得的访问令牌,我做了Mail Rest API调用从用户收件箱中获取消息。它结束了以下错误:
HTTP响应:{"错误":{"代码":"MailboxNotEnabledForRESTAPI","消息":"此邮箱尚不支持REST API。"}}
任何人都可以帮助我以下:

  • 确切原因是什么:"美国航空和航天学会90011:"不支持" resource "请求参数"在以下Outlook开发文档之后。
  • 如何解决"RESTAPI邮箱未启用"错误。
  • 是否可以使用java邮件API连接到Outlook IMAP服务器与正确的AccessToken?
uhry853o

uhry853o1#

我最近遇到了这个问题,但不记得是哪个解决了它。一个主要问题是在文档中,它是变化的。它会告诉你附加“资源”,但这是为其他东西,如Azure。
下面是我使用的代码:
发送的第一个请求:

private static final String USER_OAUTH2_AUTHORIZE_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";

      public String getOAuthDialog(Http.Request request) {
        return USER_OAUTH2_AUTHORIZE_URL
           + "?client_id=" + config.getClientId()
           + "&redirect_uri=" + getOutlookLoginRedirect(request)
           + "&response_type=code"
           + "&scope=https%3A%2F%2Foutlook.office.com%2Fmail.send%20" +
             "https%3A%2F%2Foutlook.office.com%2Fmail.readwrite%20" + 
             "offline_access%20openid%20email%20profile"
           + "&state=" + crypto.generateSignedToken();
       }

作用域是最难搞清楚的东西,我发现很多都不起作用,而且不清楚是否需要用空格分隔它们。
然后,他们将向您发送一个请求,请求您提供的重定向URL。它将包含一个代码,您需要使用该代码来交换您在作用域中请求的数据。提供的重定向URL需要完全相同。此外,您还需要在应用程序门户上的“平台”-〉“添加平台”-〉“重定向URI”-〉“添加URL”下注册重定向URL

private static final String USER_ACCESS_TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
  private Map<String, String> sendOutlookUserOAuthRequest(Http.Request request, String code) {
    WSClient ws = WS.client();

    HttpParameters params = new HttpParameters();
    params.put("client_id", config.getClientId(), true);
    params.put("client_secret", config.getClientSecret(), true);
    params.put("code", code, true);
    params.put("redirect_uri", getOutlookLoginRedirect(request), true);
    params.put("grant_type", "authorization_code");
    String postParams = OAuthUtil.parametersToString(params);

    WSRequest wsRequest = ws.url(USER_ACCESS_TOKEN_URL)
        .setMethod("POST")
        .setContentType("application/x-www-form-urlencoded")
        .setBody(postParams);

    WSResponse wsResponse = wsRequest.execute().get(10, TimeUnit.SECONDS);

    Map<String, String> result = new HashMap<>();
    if (wsResponse.getStatus() != HttpStatus.SC_OK) {
      return result;
    }

    JsonNode node = wsResponse.asJson();
    if (node.hasNonNull("access_token")) {
      result.put("access_token", node.get("access_token").asText());
    }
    if (node.hasNonNull("refresh_token")) {
      result.put("refresh_token", node.get("refresh_token").asText());
    }

    if (node.hasNonNull("id_token")) {
      String[] tokenSplit = node.get("id_token").asText().split("\\.");
      if (tokenSplit.length >= 2) {
        try {
          JSONObject jsonObject = new JSONObject(new String(Base64.getDecoder().decode(tokenSplit[1])));
          if (jsonObject.has("name")) {
            result.put("name", jsonObject.get("name").toString());
          }
          if (jsonObject.has("email")) {
            result.put("outlookUid", jsonObject.get("email").toString());
          } else if (jsonObject.has("preferred_username")) {
            result.put("outlookUid", jsonObject.get("preferred_username").toString());
          }
        } catch (JSONException e) {
          log.error("Error extracting outlookUid from id_token: ", e);
        }
      }
    }

    return result;
  }

您可能需要的另一个请求是更新刷新标记:

private String getAccessTokenFromRefreshToken(User user) {

    WSClient ws = WS.client();
    HttpParameters params = new HttpParameters();
    params.put("client_id", config.getClientId(), true);
    params.put("client_secret", config.getClientSecret(), true);
    params.put("grant_type", "refresh_token");
    params.put("refresh_token", user.getOutlookRefreshToken());
    String postParams = OAuthUtil.parametersToString(params);

    WSRequest wsRequest = ws.url(USER_ACCESS_TOKEN_URL)
        .setMethod("POST")
        .setContentType("application/x-www-form-urlencoded")
        .setBody(postParams);

    WSResponse wsResponse = wsRequest.execute().get(10, TimeUnit.SECONDS);
    if (wsResponse.getStatus() != HttpStatus.SC_OK) {
      log.error("Failure to refresh outlook access token for user: " + user +
          ". Received status: " + wsResponse.getStatus() + " : " + wsResponse.getStatusText());
      return null;
    }
    JsonNode node = wsResponse.asJson();
    if (node.hasNonNull("access_token")) {
      String accessToken = node.get("access_token").asText();
      return accessToken;
    } else {
      log.error("Outlook refresh token failure, 'access_token' not present in response body: " + wsResponse.getBody());
      return null;
    }
  }

我遇到的一个问题是,获取clientId和clientSecret的时间比我希望的要长得多。这是因为微软使用的语言不是最明确的。客户端Id和应用程序id可以互换使用。客户端密码也是您在应用程序门户上创建的密码,不要与您可以生成的私钥混淆。
因此,您实际上需要application_id和password,尽管它们将其称为client_id和client_secret,但没有直接指出所画的线。
这一切都是假设您已经在Outlook应用程序门户上设置了一个应用程序。https://apps.dev.microsoft.com/
我希望这能有所帮助,尽管我认为你可能已经解决了这个问题。

oxf4rvwz

oxf4rvwz2#

我在Java邮件中遇到了同样的问题。您需要为Azure AD上的应用程序添加服务主体。
在中型文章Complete guide: Java Mail IMAP OAuth2.0 Connect Outlook | by Ritik Sharma | Dec, 2022中找到完整的步骤说明。

相关问题