Skip to content

small fixes to 2-1-Call-MSGraph readme and small code clean up #410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;
using System.Net;
using System.Net.Http;
using Microsoft.Graph;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
Expand All @@ -26,9 +21,9 @@ public class HomeController : Controller
public HomeController(ILogger<HomeController> logger,
GraphServiceClient graphServiceClient)
{
_logger = logger;
_logger = logger;
_graphServiceClient = graphServiceClient;
}
}

[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public async Task<IActionResult> Index()
Expand Down
2 changes: 0 additions & 2 deletions 2-WebApp-graph-user/2-1-Call-MSGraph/Models/ErrorViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;

namespace _2_1_Call_MSGraph.Models
{
public class ErrorViewModel
Expand Down
6 changes: 0 additions & 6 deletions 2-WebApp-graph-user/2-1-Call-MSGraph/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace _2_1_Call_MSGraph
{
Expand Down
47 changes: 22 additions & 25 deletions 2-WebApp-graph-user/2-1-Call-MSGraph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,14 @@ After the following lines in the ConfigureServices(IServiceCollection services)
public void ConfigureServices(IServiceCollection services)
{
. . .
services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { Constants.ScopeUserRead })
.AddInMemoryTokenCaches();
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');

// Add Graph
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
```

The two new lines of code:
Expand Down Expand Up @@ -154,11 +159,15 @@ Add the `Services\*.cs` files. The `GraphServiceClientFactory.cs` returns a `Gra

### Update the `Startup.cs` file to enable the Microsoft Graph custom service

Still in the `Startup.cs` file, add the following lines just after the following. This lines ensures that the GraphAPIService benefits from the optimized `HttpClient` management by ASP.NET Core.
Still in the `Startup.cs` file, add the following `AddMicrosoftGraph` extension method. This lines ensures that the GraphAPIService benefits from the optimized `HttpClient` management by ASP.NET Core.

```CSharp
// Add Graph
services.AddGraphService(Configuration);
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
```

### Change the controller code to acquire a token and call Microsoft Graph
Expand All @@ -168,32 +177,29 @@ In the `Controllers\HomeController.cs`file:
1. Add a constructor to HomeController, making the ITokenAcquisition service available (used by the ASP.NET dependency injection mechanism)

```CSharp
readonly ITokenAcquisition tokenAcquisition;
readonly WebOptions webOptions;
private readonly GraphServiceClient _graphServiceClient;

public HomeController(ITokenAcquisition tokenAcquisition, IOptions<WebOptions> webOptionValue)
public HomeController(ILogger<HomeController> logger,
GraphServiceClient graphServiceClient)
{
this.tokenAcquisition = tokenAcquisition;
this.webOptions = webOptionValue.Value;
_logger = logger;
_graphServiceClient = graphServiceClient;
}
```

1. Add a `Profile()` action so that it calls the Microsoft Graph *me* endpoint. In case a token cannot be acquired, a challenge is attempted to re-sign-in the user, and have them consent to the requested scopes. This is expressed declaratively by the `AuthorizeForScopes`attribute. This attribute is part of the `Microsoft.Identity.Web` project and automatically manages incremental consent.

```CSharp
[AuthorizeForScopes(Scopes = new[] { Constants.ScopeUserRead })]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public async Task<IActionResult> Profile()
{
// Initialize the GraphServiceClient.
Graph::GraphServiceClient graphClient = GetGraphServiceClient(new[] { Constants.ScopeUserRead });

var me = await graphClient.Me.Request().GetAsync();
var me = await _graphServiceClient.Me.Request().GetAsync();
ViewData["Me"] = me;

try
{
// Get user photo
using (var photoStream = await graphClient.Me.Photo.Content.Request().GetAsync())
using (var photoStream = await _graphServiceClient.Me.Photo.Content.Request().GetAsync())
{
byte[] photoByte = ((MemoryStream)photoStream).ToArray();
ViewData["Photo"] = Convert.ToBase64String(photoByte);
Expand All @@ -206,15 +212,6 @@ public async Task<IActionResult> Profile()

return View();
}

private Graph::GraphServiceClient GetGraphServiceClient(string[] scopes)
{
return GraphServiceClientFactory.GetAuthenticatedGraphClient(async () =>
{
string result = await tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes);
return result;
}, webOptions.GraphApiUrl);
}
```

### Add a Profile view to display the *me* object
Expand Down
63 changes: 28 additions & 35 deletions 2-WebApp-graph-user/2-1-Call-MSGraph/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Graph;

namespace _2_1_Call_MSGraph
{
Expand All @@ -33,37 +26,37 @@ public void ConfigureServices(IServiceCollection services)
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();

/*
// or use a distributed Token Cache by adding
.AddDistributedTokenCaches();
/*
// or use a distributed Token Cache by adding
.AddDistributedTokenCaches();

// and then choose your implementation.
// See https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2#distributed-memory-cache
// and then choose your implementation.
// See https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2#distributed-memory-cache

// For instance the distributed in memory cache
services.AddDistributedMemoryCache()
// For instance the distributed in memory cache
services.AddDistributedMemoryCache()

// Or a Redis cache
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "SampleInstance";
});
// Or a Redis cache
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "SampleInstance";
});

// Or even a SQL Server token cache
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString =
_config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
*/
// Or even a SQL Server token cache
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString =
_config["DistCache_ConnectionString"];
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
*/

services.AddControllersWithViews(options =>
{
Expand All @@ -72,8 +65,8 @@ public void ConfigureServices(IServiceCollection services)
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand Down