EWS GetUserPhoto 委派给仅应用程序身份验证

EWS GetUserPhoto Delegated to App-Only Authentication

我目前正在使用委托授权获取用户照片,如下所示:

var pcaOptions = new PublicClientApplicationOptions
{
    ClientId = "ClientID",
    TenantId = "TenantId"
};

var pca = PublicClientApplicationBuilder.CreateWithApplicationOptions(pcaOptions).Build();
var ewsScopes = new string[] { "https://outlook.office365.com/EWS.AccessAsUser.All" };
var authResult = await pca.AcquireTokenInteractive(ewsScopes).ExecuteAsync();

string email = "SomeEmail@email.com";
HttpWebRequest request = WebRequest.Create(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email)) as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){
    Stream stream = response.GetResponseStream();
    using (MemoryStream ms = new MemoryStream())
    {
        string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
    }
}

我正在尝试更改为使用仅应用程序身份验证。我设法获得了访问令牌,但似乎无法像委托授权那样完成。

以下是我切换到使用仅应用程序身份验证所做的操作。

var cca = ConfidentialClientApplicationBuilder
                .Create("ClientID")
                .WithClientSecret("ClientSecret")
                .WithTenantId("TenantID")
                .Build();

var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();

string email = "SomeEmail@email.com";
HttpWebRequest request = WebRequest.Create(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email)) as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){
//Error: The remote server returned an error: (400) Bad Request.
    Stream stream = response.GetResponseStream();
    using (MemoryStream ms = new MemoryStream())
    {
        string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
    }
}

错误:远程服务器返回错误:(400) 错误请求。

编辑:已更新为使用 SOAP 操作,如下所示,但我收到此错误:“远程服务器返回错误:(500) 内部服务器错误。”

有什么我可能遗漏的吗?

var cca = ConfidentialClientApplicationBuilder
                .Create("ClientID")
                .WithClientSecret("ClientSecret")
                .WithTenantId("TenantID")
                .Build();

var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();

HttpWebRequest request = WebRequest.Create("https://outlook.office365.com/EWS/Exchange.asmx") as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
request.Method = "POST";

XmlDocument SOAPReqBody = new XmlDocument();

SOAPReqBody.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8"" ?>
                    <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:t=""https://schemas.microsoft.com/exchange/services/2006/types"" xmlns:m=""https://schemas.microsoft.com/exchange/services/2006/messages"">
                        <soap:Header>
                        <t:RequestServerVersion Version=""Exchange2013""/>
                        <t:ExchangeImpersonation>
                            <t:ConnectingSID>
                            <t:PrimarySmtpAddress>impersonatedUser@mail.com</t:PrimarySmtpAddress>
                            </t:ConnectingSID>
                        </t:ExchangeImpersonation>
                        </soap:Header>
                        <soap:Body>
                        <m:GetUserPhoto>
                            <m:Email>UserEmail@mail.com</m:Email>
                            <m:SizeRequested>HR648x648</m:SizeRequested>
                        </m:GetUserPhoto>
                        </soap:Body>
                    </soap:Envelope>");

using (Stream stream = request.GetRequestStream())
{
      SOAPReqBody.Save(stream);
}

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){
//The remote server returned an error: (500) Internal Server Error.
    Stream stream = response.GetResponseStream();
    using (MemoryStream ms = new MemoryStream())
    {
        string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
    }
}

EWS 中的应用程序令牌要求您模拟已知用户(当您请求然后采用该身份),因此您需要使用 SOAP 操作 https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuserphoto-operation 然后模拟真实用户(如果你有应用程序策略,你需要小心,否则租户中的任何用户都应该工作)例如

       var cca = ConfidentialClientApplicationBuilder
                        .Create("d4")
                        .WithClientSecret("s")
                        .WithTenantId("x")
                        .Build();

        var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
        var authResult = cca.AcquireTokenForClient(ewsScopes).ExecuteAsync().Result;


        HttpWebRequest request = WebRequest.Create("https://outlook.office365.com/EWS/Exchange.asmx") as HttpWebRequest;
        request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
        request.Method = "POST";

        XmlDocument SOAPReqBody = new XmlDocument();

        SOAPReqBody.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?>
        <soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:m=""http://schemas.microsoft.com/exchange/services/2006/messages"" xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
          <soap:Header>
            <t:RequestServerVersion Version=""Exchange2016"" />
            <t:ExchangeImpersonation>
              <t:ConnectingSID>
                <t:SmtpAddress>user@domain.com</t:SmtpAddress>
              </t:ConnectingSID>
            </t:ExchangeImpersonation>
          </soap:Header>
          <soap:Body>
            <m:GetUserPhoto>
              <m:Email>user@domain.com</m:Email>
              <m:SizeRequested>HR48x48</m:SizeRequested>
            </m:GetUserPhoto>
          </soap:Body>
        </soap:Envelope>");

        using (Stream stream = request.GetRequestStream())
        {
            SOAPReqBody.Save(stream);
        }

        using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
            //The remote server returned an error: (500) Internal Server Error.
            Stream stream = response.GetResponseStream();
            XmlDocument Response = new XmlDocument();
            Response.Load(stream);
            var PictureDataNodes = Response.GetElementsByTagName("PictureData");
            Byte[] PictureData = Convert.FromBase64String(PictureDataNodes[0].InnerText);
            File.WriteAllBytes("c:\temp\pictest.jpg", PictureData);
        }
    }