c# - 无法使用客户端 ID 和密码访问用户照片

标签 c# azure office365 azure-active-directory microsoft-graph-api

我尝试使用统一 API (Microsoft.Graph 1.0.1) 访问我的用户个人资料照片,但在访问照片时仅收到以下错误:

Code: ErrorAccessDenied
Message: Access is denied. Check credentials and try again.

访问/列出其他用户配置文件数据工作正常,我的应用程序已通过 PowerShell 添加为“公司管理员”并拥有管理门户中设置的所有权限。当我使用GraphExlorer时使用我的管理员用户登录它也可以正常工作。另外,通过“旧”Azure Active Directory Graph API,我可以读取/写入用户缩略图照片,但这不是 Office 365 中显示的照片。

如何获得适当的访问权限来对用户个人资料照片执行操作?

这是我使用的代码(缩写为有问题的部分):

class Program
{
    private const string authStringMicrosoft = "https://login.microsoftonline.com/MY_APP_ID/";

    private const string clientID = "MY_CLIENT_ID";
    private const string clientSecret = "MY_CLIENT_SECRET";

    private const string graphResourceId = "https://graph.microsoft.com";

    static void Main(string[] args)
    {
        AsyncContext.Run(RunAsync);

        Console.WriteLine("DONE");
        Console.ReadLine();
    }

    private static async Task RunAsync()
    {
        var token = await GetAppTokenAsync(authStringMicrosoft, graphResourceId);
        var authHelper = new AuthenticationHelper() { AccessToken = token }
        var graphClient = new GraphServiceClient(authHelper);
        await ListUser(graphClient);
    }

    private static async Task ListUser(GraphServiceClient graphClient)
    {
        Console.WriteLine("User-List:");
        var users = await graphClient.Users.Request().GetAsync();
        foreach (var user in users)
        {
            Console.WriteLine($"{user.UserPrincipalName}:\t\t{user.GivenName} {user.Surname}");
            if (user.UserPrincipalName == "USER_WITH_PICTURE")
            {
                var graphUser = graphClient.Users[user.UserPrincipalName];
                var graphPhoto = graphUser.Photo;

                var photoInfo = await graphPhoto.Request().GetAsync(); // <= here the exceptions is thrown
                Console.WriteLine($"{photoInfo.Id}:\t{photoInfo.Width}x{photoInfo.Height}");

                var photoStream = await graphPhoto.Content.Request().GetAsync();

                byte[] photoByte = new byte[photoStream.Length];
                photoStream.Read(photoByte, 0, (int)photoStream.Length);
                File.WriteAllBytes(@"D:\User.jpg", photoByte);
            }
        }
    }

    private static async Task<string> GetAppTokenAsync(string authority, string azureGraphAPI)
    {
        var authenticationContext = new AuthenticationContext(authority);
        var clientCred = new ClientCredential(clientID, clientSecret);
        var authenticationResult = await authenticationContext.AcquireTokenAsync(azureGraphAPI, clientCred);
        return authenticationResult.AccessToken;
    }
}

public class AuthenticationHelper : IAuthenticationProvider
{
    public string AccessToken { get; set; }

    public Task AuthenticateRequestAsync(HttpRequestMessage request)
    {
        request.Headers.Add("Authorization", "Bearer " + AccessToken);
        return Task.FromResult(0);
    }
}

我使用以下 NuGet 包:

<packages>
  <package id="Microsoft.Data.Edm" version="5.7.0" targetFramework="net46" />
  <package id="Microsoft.Data.OData" version="5.7.0" targetFramework="net46" />
  <package id="Microsoft.Data.Services.Client" version="5.7.0" targetFramework="net46" />
  <package id="Microsoft.Graph" version="1.0.1" targetFramework="net46" />
  <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.24.304111323" targetFramework="net46" />
  <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net46" />
  <package id="Nito.AsyncEx" version="3.0.1" targetFramework="net46" />
  <package id="System.Spatial" version="5.7.0" targetFramework="net46" />
</packages>

这是一个传递错误的示例请求(使用 postman 和从上面的应用程序读出的 token ):

GET /v1.0/users/MY_USER_WITH_PHOTO/photo/ HTTP/1.1
Host: graph.microsoft.com
Connection: keep-alive
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1...
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
Postman-Token: e756a8a3-22e2-d40c-8e52-15c4d1aa7468
Accept: /
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de,en-US;q=0.8,en;q=0.6

响应:

HTTP/1.1 403 Forbidden
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: application/json
Server: Microsoft-IIS/8.5
request-id: 96e8dda8-2353-4891-8c42-99cfe7e22887
client-request-id: 96e8dda8-2353-4891-8c42-99cfe7e22887
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"North Europe","Slice":"SliceA","ScaleUnit":"001","Host":"AGSFE_IN_4","ADSiteName":"DUB"}} Duration: 1367.7691
X-Powered-By: ASP.NET
Date: Sun, 01 May 2016 17:57:02 GMT

正文:

{
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again.", "innerError": {
"request-id": "96e8dda8-2353-4891-8c42-99cfe7e22887",
"date": "2016-05-01T17:57:02"
}
}
}

同样,如果我从请求中删除 /photo,我就可以毫无问题地获取所有常见用户详细信息。

这是我的应用程序(网络应用程序)的权限: permissions

这里是解密的访问 token :

{
 typ: "JWT",
 alg: "RS256",
 x5t: "MnC_VZcATfM5pOYiJHMba9goEKY",
 kid: "MnC_VZcATfM5pOYiJHMba9goEKY"
}.
{
 aud: "https://graph.microsoft.com",
 iss: "https://sts.windows.net/11205e59-fa81-480f-b497-571579c5389a/",
 iat: 1462795409,
 nbf: 1462795409,
 exp: 1462799309,
 appid: "c34a87ef-352a-4af4-a166-eb7e521a0ec9",
 appidacr: "1",
 idp: "https://sts.windows.net/11205e59-fa81-480f-b497-571579c5389a/",
 oid: "1db8c6b5-10ba-40ac-bbff-86ab440c4fd3",
 roles: [
  "Mail.ReadWrite",
  "Device.ReadWrite.All",
  "User.ReadWrite.All",
  "Calendars.Read",
  "Group.Read.All",
  "Directory.ReadWrite.All",
  "Contacts.ReadWrite",
  "Group.ReadWrite.All",
  "Directory.Read.All",
  "User.Read.All",
  "Mail.Read",
  "Calendars.ReadWrite",
  "Mail.Send",
  "MailboxSettings.ReadWrite",
  "Contacts.Read"
 ],
 sub: "1db8c6b5-10ba-40ac-bbff-86ab440c4fd3",
 tid: "11205e59-fa81-480f-b497-571579c5389a",
 ver: "1.0"
}

最佳答案

以防万一其他人在收到该错误时阅读此内容。我在创建自己的 graphClient 时遇到了同样的错误,我得到它的原因是由于使用非管理员帐户...

var users = await graphClient.Users.Request().Select().GetAsync();

使用非管理员帐户,您只能访问一些基本属性,例如姓氏、名字等 - 这对我有用...

var users = await graphClient.Users.Request().Select("mail,givenName,surname").GetAsync();

关于c# - 无法使用客户端 ID 和密码访问用户照片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36968052/

相关文章:

php - Outlook API 中的 403 错误访问被拒绝

email - Jenkins 和 Office365 电子邮件通知设置

android - Azure 移动服务,应用程序崩溃(离线同步 - Android)

c# - 在 Azure Function .net 5 中处理 blob 触发器时出现 Microsoft.Azure.Functions.Worker.Diagnostics.Exceptions.FunctionInputConverterException

azure - Authorization_IdentityNotFound 访问图形 API 时出错

c# - 是否有任何有值(value)的 CSLA 替代品可用?

c# - 将位置从 3D 相机转换为 2D 相机

c# - 模拟 IOrganizationService (Dynamics CRM) 时未过滤 LINQ 查询结果

c# - 检测非 DPI 感知应用程序是否已缩放/虚拟化

azure - 如何将 Windows 开发人员中心仪表板/使用页面中的检测 key 添加到 Azure 门户?