Microsoft Graph访问我

时间:2017-08-28 16:19:32

标签: c# asp.net azure microsoft-graph

我有一个应用程序设置,使用Azure AD(工作或学校帐户)将用户登录到应用程序。我还希望能够使用委托权限从此应用程序查询Microsoft Graph。我相信我设置的是使用应用程序权限,但我没有看到我错过了正确设置此设置。该应用程序是ASP.NET Core 2应用程序。

在我的Startup.cs中,我有以下代码。

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddAzureAd(options => Configuration.Bind("AzureAd", options))
    .AddCookie();

    services.AddMvc();

    services.AddSingleton(Configuration);
    services.AddSingleton<IGraphAuthProvider, GraphAuthProvider>();
    services.AddTransient<IGraphSDKHelper, GraphSDKHelper>();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

AddAzureAd是这里定义的扩展方法:

与Marc合作后 我发现问题是下面的OnAuthorizationCodeReceived事件永远不会触发。我不知道为什么,但这是问题的根源。

public static class AzureAdAuthenticationBuilderExtensions
{        
    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
        => builder.AddAzureAd(_ => { });

    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
    {
        builder.Services.Configure(configureOptions);
        builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
        builder.AddOpenIdConnect(opts =>
        {
            opts.Events = new OpenIdConnectEvents
            {
                OnAuthorizationCodeReceived = async ctx =>
                {
                    var request = ctx.HttpContext.Request;
                    var currentUri =
                        UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
                    var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);

                    var distributedCache = ctx.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
                    var userId = ctx.Principal
                        .FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
                        .Value;
                    var cache = new AdalDistributedTokenCache(distributedCache, userId);
                    var authContext = new AuthenticationContext(ctx.Options.Authority, cache);
                    var result = await authContext.AcquireTokenByAuthorizationCodeAsync(ctx.ProtocolMessage.Code,
                        new Uri(currentUri), credential, ctx.Options.Resource);
                    ctx.HandleCodeRedemption(result.AccessToken, result.IdToken);
                }
            };
        });
        return builder;
    }

    private class ConfigureAzureOptions: IConfigureNamedOptions<OpenIdConnectOptions>
    {
        private readonly AzureAdOptions _azureOptions;

        public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
        {
            _azureOptions = azureOptions.Value;
        }

        public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ClientId = _azureOptions.ClientId;
            options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
            options.UseTokenLifetime = true;
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;
        }

        public void Configure(OpenIdConnectOptions options)
        {
            Configure(Options.DefaultName, options);
        }
    }
}

AdalDistributeTokenCache类如下所示:

    internal class AdalDistributedTokenCache : TokenCache
    {
        private readonly IDistributedCache cache;
        private readonly string userId;

        public AdalDistributedTokenCache(IDistributedCache cache, string userId)
        {
            this.cache = cache;
            this.userId = userId;

            BeforeAccess = OnBeforeAccess;
            AfterAccess = OnAfterAccess;
        }

        private void OnBeforeAccess(TokenCacheNotificationArgs args)
        {
            var userTokenCachePayload = cache.Get(CacheKey);
            if (userTokenCachePayload != null)
            {
                Deserialize(userTokenCachePayload);
            }
        }

        private void OnAfterAccess(TokenCacheNotificationArgs args)
        {
            if (HasStateChanged)
            {
                var cacheOptions = new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(14)
                };

                cache.Set(CacheKey, Serialize(), cacheOptions);

                HasStateChanged = false;
            }
        }

        private string CacheKey => $"TokenCache_{userId}";
    }
}

从我读过的所有内容来看,这似乎是我正在尝试做的正确设置。现在在主页控制器中我有以下代码

public async Task<IActionResult> Index(string email)
{
    // Get users's email.
    email = email ?? User.Identity.Name;
    ViewData["Email"] = email;

    // Get user's id for token cache.
    var identifier = User.FindFirst(Startup.ObjectIdentifierType)?.Value;

    // Initialize the GraphServiceClient.
    var graphClient = _graphSdkHelper.GetAuthenticatedClient(identifier);

    ViewData["Response"] = await GraphService.GetUserJson(graphClient, email);
    ViewData["Response"] = await GraphService.GetMeJson(graphClient, email);

    //ViewData["Picture"] = await GraphService.GetPictureBase64(graphClient, email);
    var groups = await GraphService.GetGroups(graphClient);
    return View();
}

表示GetUserJson工作的行并调用一个看起来像这样的方法

var user = await graphClient.Users[email].Request().GetAsync();
return JsonConvert.SerializeObject(user, Formatting.Indented);

说GetMeJson的行确实起作用并且通过错误看起来像

var user = await graphClient.Me.Request().GetAsync();
return JsonConvert.SerializeObject(user, Formatting.Indented);

最后一段代码是GetAuthenticatedClient,它看起来像

public GraphServiceClient GetAuthenticatedClient(string userId)
{
    _graphClient = new GraphServiceClient("https://graph.microsoft.com/beta", new DelegateAuthenticationProvider(
        async (requestMessage) =>
        {
            // Passing tenant ID to the sample auth provider to use as a cache key
            AccessToken = await _authProvider.GetUserAccessTokenAsync(userId);

            // Append the access token to the request
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
        }));

    return _graphClient;
}

我得到的错误信息是:

Microsoft.Graph.ServiceException: 
   Code: Request_ResourceNotFound
   Message: Resource '40f381c1-55f3-4295-99e3-0309a704374e' does not 
            exist or one of its queried reference-property objects 
            are not present.

有人可以帮助我克服这个障碍,所以我可以将Graph API称为经过身份验证的用户。

*********** Marc *************的其他信息请求

该应用程序通过portal.azure.com注册,并具有以下权限。

在Microsoft Graph下 在应用程序权限下,User.Read.All,Directory.Read.All,Group.Read.All 在委派权限,个人资料(查看用户&#39;基本个人资料),电子邮件(查看用户&#39;电子邮件地址),Directory.Read.All。 Group.Read.All,User.Read.All,User.ReadBasic.All

在Windows Azure Active Directory下 在委派权限下:User.Read(登录并阅读用户配置文件)

我现在知道我不应该需要应用程序权限,并且可以在某些时候删除它们,但我没有权限这样做,需要让其他人为我这样做。< / p>

**********调试令牌********* 我在第

行放了一个断点
AccessToken = await _authProvider.GetUserAccessTokenAsync(userId);

然后拿起它到达的AccessToken并将其放入calebb.net并获得以下结果。

{
 typ: "JWT",
 nonce: "bunch of letters",
 alg: "RS256",
 x5t: "bunch of letters",
 kid: "bunch of letters"
}.
{
 aud: "https://graph.microsoft.com/",
 iss: "https://sts.windows.net/dde15eeb-a6bd-46a2-9f03-d44429074ecf/",
 iat: 1503942101,
 nbf: 1503942101,
 exp: 1503946001,
 aio: "bunch of letters",
 app_displayname: "Test App",
 appid: "Guid",
 appidacr: "1",
 e_exp: 262800,
 idp: "https://sts.windows.net/dde15eeb-a6bd-46a2-9f03-d44429074ecf/",
 oid: "Guid",
 roles: [
  "Group.Read.All",
  "Directory.Read.All",
  "User.Read.All"
 ],
 sub: "Guid",
 tid: "Guid",
 uti: "bunch of letters",
 ver: "1.0"
}.
[signature]

您怀疑它仅作为应用程序权限而不是委托权限。那么它获取令牌的这一部分有什么问题。我在这里显然没有做正确的身份验证,但我不知道自己做错了什么。

public async Task<string> GetUserAccessTokenAsync(string userId)
{
    TokenCache userTokenCache = new SessionTokenCache(userId, _memoryCache).GetCacheInstance();

    try
    {
        AuthenticationContext authContext = new AuthenticationContext(_aadInstance, userTokenCache);
        ClientCredential credential = new ClientCredential(_appId, _appSecret);
        AuthenticationResult result = await authContext.AcquireTokenAsync(_graphResourceId, credential);

        return result.AccessToken;
    }
    catch (Exception ex)
    {
        return null;
    }
}

0 个答案:

没有答案