【问题标题】:Getting Error code 403 while accessing Office 365 mail box for the client credential grant flow访问客户端凭据授予流程的 Office 365 邮箱时出现错误代码 403
【发布时间】:2015-05-26 10:35:56
【问题描述】:

我正在尝试连接到 Office 365 以使用客户端凭据流。我已按照http://blogs.msdn.com/b/exchangedev/archive/2015/01/21/building-demon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow.aspx 中提到的所有步骤进行操作

我正在尝试使用 ADAL java 库进行连接。

使用以下代码连接和获取邮件:

String authority = "https://login.windows.net/tenant-id/oauth2/authorize";
ExecutorService service = null;
service=Executors.newFixedThreadPool(1);
try {
    AuthenticationContext authenticationContext =  new AuthenticationContext(authority, false, service);
    String certfile = "PfxFinal.pfx";
    InputStream pkcs12Certificate=new FileInputStream(certfile);

    String token = "";

    AsymmetricKeyCredential credential = AsymmetricKeyCredential.create("clientid", pkcs12Certificate,"password");
    System.out.println("X509 is fine!");

    Future<AuthenticationResult> future=authenticationContext.acquireToken("https://outlook.office365.com", (AsymmetricKeyCredential)credential, null);// authenticationContext.acquireToken("https://outlook.office365.com", credential, null);
    System.out.println("Token Received "+future.get().getAccessToken());
    token=future.get().getAccessToken();
    System.out.println(token);


    URL url = new URL("https://outlook.office365.com/api/v1.0/me/folders/inbox/messages?$count=true&$filter=isread%20eq%20false");
    HttpURLConnection con = (HttpURLConnection) url.openConnection(); 
    con.setRequestMethod("GET"); 
    con.setRequestProperty("Accept","application/json"); 
    //con.setRequestProperty("Authorization",token);
    con.setRequestProperty("Authorization","Bearer "+token);
    System.out.println("Bearer "+token);

    if (con.getResponseCode() != 200) {
        throw new RuntimeException("Failed : HTTP error code : "
                + con.getResponseCode());
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(
        (con.getInputStream())));

    String output;
    System.out.println("Output from Server .... \n");
    while ((output = br.readLine()) != null) {
        System.out.println(output);
    }

    con.disconnect();
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

我已为租户提供了完全许可。是否还有其他事情需要我做才能解决此问题。

【问题讨论】:

    标签: ms-office office365 office365-apps


    【解决方案1】:

    您正在寻址“/me”端点,对于“仅限应用程序”访问实际上没有任何意义,因为“me”代表一个邮箱,并且访问令牌没有可用于确定“我”的用户上下文邮箱试图访问。对于仅限应用程序的访问令牌,您必须使用用户(“要访问的邮箱电子邮件地址”)。 “app-only”表示没有邮箱或用户信息的应用程序标识。

    如果您仍有问题,请告诉我。

    谢谢, 马蒂亚斯

    【讨论】:

    • 嗨 Matthias,我现在添加了以下 URL,用于调用收件箱中的邮件列表:outlook.office365.com/api/v1.0/emailaddress/folders/inbox/…。但是,我现在得到错误代码 400。这一行是否正确: con.setRequestProperty("Authorization","Bearer"+token);或者这应该是 con.setRequestProperty("Authorization",token);
    • 您需要将标头设置为“授权:承载令牌”。在 400 中,您是否在某些标题中获得了一些额外的信息?例如。您看到 x-ms-diagnostics 标头了吗?您能否将访问令牌复制并粘贴到 jwt.calebb.net 并检查“角色”声明类型中的内容。
    • 访问令牌的角色是 "full_access_as_app", "Mail.Read","Mail.Send" 。我没有在标题中获得 x-ms-diagnostics。
    • 下面是头信息,通过con.getHeaderFields(): {null= [HTTP/1.1 401 Unauthorized], WWW-Authenticate=[Basic Realm=""], Content-Length=[0 ], request-id=[305f6089-026f-43d7], Set-Cookie=[ClientId=HVVBULC0A;到期=格林威治标准时间 2016 年 5 月 26 日星期四 10:59:35;路径=/;安全的; HttpOnly], X-WSSecurity-X509Cert-Enabled=[True], Server=[Microsoft-IIS/8.0], X-Powered-By=[ASP.NET], X-OAuth-Enabled=[True], X-FederationTrustTokenIssuerUri =[urn:federation:MicrosoftOnline], X-WSSecurity-For=[Logon], X-FEServer=[SGR03], X-WSSecurity-SymmetricKey-Enabled=[True], X-WSSecurity-Enabled=[True]}
    • 另外,根据您的博客,在上传清单文件时,“keyCredentials”下的 $base64Value_from_above 对于 value ,当我重新下载它进行验证时,它变为 null 。不过,我可以上传所有详细信息。这是预期的吗?最后,在注册 web 应用程序时,在 azure 管理门户中,我为应用程序 url id 提供了一个标准的 web url(如 gmail),而不是自定义的,因为我还没有任何 url。在创建我们自己的网址之前,我们可以使用任何标准网址吗?如果我这样做,这会是个问题吗?
    【解决方案2】:

    在 Azure AD 中注册应用程序时,您配置了哪些 Exchange Online 权限?您应该拥有Read mail in all mailboxesRead and write mail in all mailboxes

    【讨论】:

    • 我实际上已经给了 access , Read 和 Read/Write 。我现在才授予读写访问权限。此外,正如 Mathias 所建议的,我已将 /me 替换为实际的电子邮件地址。但是,我现在收到错误 400。想知道是否行 con.setRequestProperty("Authorization", "Bearer" + token);是正确的 。当我删除 Bearer 时,我会收到错误 401。
    【解决方案3】:

    这已解决,下面是完整的工作代码:

    公共类 AccessToken { public static void main(String[] args) {

    String authority = "https://login.windows.net/xxxxxxxxxxxxx/oauth2/authorize";
    ExecutorService service = null;
    service=Executors.newFixedThreadPool(1);
    try {
        AuthenticationContext authenticationContext =  new AuthenticationContext(authority, false, service);
        String certfile = "pfx.pfx";
        InputStream pkcs12Certificate=new FileInputStream(certfile);
    
        String token = "";
    
    
        AsymmetricKeyCredential credential = AsymmetricKeyCredential.create("id", pkcs12Certificate,"password");
        System.out.println("X509 is fine!");
    
        Future<AuthenticationResult> future=authenticationContext.acquireToken("https://outlook.office365.com", (AsymmetricKeyCredential)credential, null);
    
        token=future.get().getAccessToken();
    
        Long uuid = UUID.randomUUID().getMostSignificantBits();
    
    
        URL url = new URL("https://outlook.office365.com/api/v1.0/users/email/folders/inbox/messages");
        HttpURLConnection con = (HttpURLConnection) url.openConnection(); 
    
        con.setRequestMethod("GET"); 
        con.setRequestProperty("Accept","application/json"); 
        con.setRequestProperty("User-Agent","Testing/1.0 abc/1.1");
        Date date = new Date();
    
        SimpleDateFormat ft = 
                  new SimpleDateFormat ("E, dd MM yyyy hh:mm:ss zzz");
    
                  System.out.println("Current Date: " + ft.format(date));
                  String dateString = ft.format(date);
    
    
    
        con.setRequestProperty("Authorization","Bearer "+token);
    
    
        if (con.getResponseCode() != 200) {
            System.out.println(con.getHeaderFields());
    
            throw new RuntimeException("Failed : HTTP error code : "
                    + con.getResponseCode());
    
        }
    
        BufferedReader br = new BufferedReader(new InputStreamReader(
            (con.getInputStream())));
    
        String output;
        System.out.println("Output from Server .... \n");
        while ((output = br.readLine()) != null) {
            System.out.println(output);
        }
    
        con.disconnect();
    
        service.shutdown();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    

    } }

    我能够从 office 365 获取 json 响应。我测试的另一种方法是使用 Firefox 的 RestClient 插件,以及生成的访问令牌。

    【讨论】:

      猜你喜欢
      • 2017-07-15
      • 1970-01-01
      • 1970-01-01
      • 2019-12-03
      • 2017-03-04
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      • 2020-01-20
      相关资源
      最近更新 更多