Skip to content

Commit 7b04297

Browse files
authored
Sync with ASP.NET Core Web app tutorial's Microsoft.Identity.Web (#113)
* Sync with ASP.NET Core Web app tutorial's Microsoft.Identity.Web * a few small edits (#114)
1 parent 658cecd commit 7b04297

16 files changed

+89
-333
lines changed

Microsoft.Identity.Web/README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,49 @@ In order to troubleshoot your web API you can set the `subscribeToJwtBearerMiddl
338338

339339
In both cases, you can set a breakpoint in the methods of the `OpenIdConnectMiddlewareDiagnostics` and `JwtBearerMiddlewareDiagnostics` classes respectively to observe values under the debugger.
340340

341-
## Learn more how the library works
341+
## More customizations
342+
343+
If you want to customize the `OpenIdConnectOption` or `JwtBearerOption` but still want to benefit from the implementation provided by Microsoft.Identity.Web, you can easily do it from your `Startup.cs` file:
344+
345+
Let's take for example the method `AddProtectedWebApi`. If you check the code inside it, you have this event setup:
346+
347+
```
348+
options.Events.OnTokenValidated = async context =>
349+
{
350+
// This check is required to ensure that the Web API only accepts tokens from tenants where it has been consented and provisioned.
351+
if (!context.Principal.Claims.Any(x => x.Type == ClaimConstants.Scope)
352+
&& !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Scp)
353+
&& !context.Principal.Claims.Any(y => y.Type == ClaimConstants.Roles))
354+
{
355+
throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
356+
}
357+
358+
await Task.FromResult(0);
359+
};
360+
```
361+
362+
Let's say you want to augment the current `ClaimsPrincipal` by adding claims to it, and you have to do it on `OnTokenValidated `, however you don't want to lose this `UnauthorizedAccessException` check existing in the event. To do so, on your `Startup.cs` you would have:
363+
364+
```
365+
services.AddProtectedWebApi(Configuration);
366+
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
367+
{
368+
var existingOnTokenValidatedHandler = options.Events.OnTokenValidated ;
369+
options.Events.OnTokenValidated = async context =>
370+
{
371+
await existingOnTokenValidatedHandler(context);
372+
// your code to add extra claims that will be executed after the current event implementation.
373+
}
374+
}
375+
376+
```
377+
378+
## Learn more about how the library works
342379

343380
You can learn more about the tokens by looking at the following articles in MSAL.NET's conceptual documentation:
344381

345382
- The [Authorization code flow](https://aka.ms/msal-net-authorization-code), which is used, after the user signed-in with Open ID Connect, in order to get a token and cache it for a later use. See [TokenAcquisition L 107](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/f99e913cc032e16c59b748241111e97108e87918/Extensions/TokenAcquisition.cs#L107) for details of this code
346-
- [AcquireTokenSilent](https://aka.ms/msal-net-acquiretokensilent ), which is used by the controller to get an access token for the downstream API. See [TokenAcquisition L 168](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/f99e913cc032e16c59b748241111e97108e87918/Extensions/TokenAcquisition.cs#L168) for details of this code
383+
- [AcquireTokenSilent](https://aka.ms/msal-net-acquiretokensilent), which is used by the controller to get an access token for the downstream API. See [TokenAcquisition L 168](https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/blob/f99e913cc032e16c59b748241111e97108e87918/Extensions/TokenAcquisition.cs#L168) for details of this code
347384
- [Token cache serialization](msal-net-token-cache-serialization)
348385

349386
The token validation is performed by the classes of the [Identity Model Extensions for DotNet](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) library. Learn about customizing

Microsoft.Identity.Web/TokenAcquisition.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ public class TokenAcquisition : ITokenAcquisition
2929
private readonly AzureADOptions _azureAdOptions;
3030
private readonly ConfidentialClientApplicationOptions _applicationOptions;
3131

32-
private readonly IMsalAppTokenCacheProvider _appTokenCacheProvider;
33-
private readonly IMsalUserTokenCacheProvider _userTokenCacheProvider;
32+
private readonly IMsalTokenCacheProvider _tokenCacheProvider;
3433

3534
private IConfidentialClientApplication application;
3635
private readonly IHttpContextAccessor _httpContextAccessor;
@@ -42,20 +41,18 @@ public class TokenAcquisition : ITokenAcquisition
4241
/// This constructor is called by ASP.NET Core dependency injection
4342
/// </summary>
4443
/// <param name="configuration"></param>
45-
/// <param name="appTokenCacheProvider">The App token cache provider</param>
44+
/// <param name="tokenCacheProvider">The App token cache provider</param>
4645
/// <param name="userTokenCacheProvider">The User token cache provider</param>
4746
public TokenAcquisition(
48-
IMsalAppTokenCacheProvider appTokenCacheProvider,
49-
IMsalUserTokenCacheProvider userTokenCacheProvider,
47+
IMsalTokenCacheProvider tokenCacheProvider,
5048
IHttpContextAccessor httpContextAccessor,
5149
IOptions<AzureADOptions> azureAdOptions,
5250
IOptions<ConfidentialClientApplicationOptions> applicationOptions)
5351
{
5452
_httpContextAccessor = httpContextAccessor;
5553
_azureAdOptions = azureAdOptions.Value;
5654
_applicationOptions = applicationOptions.Value;
57-
_appTokenCacheProvider = appTokenCacheProvider;
58-
_userTokenCacheProvider = userTokenCacheProvider;
55+
_tokenCacheProvider = tokenCacheProvider;
5956
}
6057

6158
/// <summary>
@@ -170,6 +167,7 @@ public async Task<string> GetAccessTokenOnBehalfOfUserAsync(
170167
throw new ArgumentNullException(nameof(scopes));
171168
}
172169

170+
// Use MSAL to get the right token to call the API
173171
var application = GetOrBuildConfidentialClientApplication();
174172
string accessToken;
175173

@@ -232,7 +230,7 @@ public async Task RemoveAccountAsync(RedirectContext context)
232230
if (account != null)
233231
{
234232
await app.RemoveAsync(account).ConfigureAwait(false);
235-
_userTokenCacheProvider?.ClearAsync().ConfigureAwait(false);
233+
_tokenCacheProvider?.ClearAsync().ConfigureAwait(false);
236234
}
237235
}
238236

@@ -266,7 +264,7 @@ private IConfidentialClientApplication BuildConfidentialClientApplication()
266264
request.PathBase,
267265
azureAdOptions.CallbackPath ?? string.Empty);
268266

269-
string authority = $"{azureAdOptions.Instance}{azureAdOptions.TenantId}/";
267+
string authority = $"{applicationOptions.Instance}{applicationOptions.TenantId}/";
270268

271269
var app = ConfidentialClientApplicationBuilder
272270
.CreateWithApplicationOptions(applicationOptions)
@@ -275,8 +273,8 @@ private IConfidentialClientApplication BuildConfidentialClientApplication()
275273
.Build();
276274

277275
// Initialize token cache providers
278-
_appTokenCacheProvider?.InitializeAsync(app.AppTokenCache);
279-
_userTokenCacheProvider?.InitializeAsync(app.UserTokenCache);
276+
_tokenCacheProvider?.InitializeAsync(app.AppTokenCache);
277+
_tokenCacheProvider?.InitializeAsync(app.UserTokenCache);
280278

281279
return app;
282280
}

Microsoft.Identity.Web/TokenCacheProviders/Distributed/DistributedTokenCacheAdapterExtension.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static IServiceCollection AddDistributedAppTokenCache(
2929
this IServiceCollection services)
3030
{
3131
services.AddDistributedMemoryCache();
32-
services.AddSingleton<IMsalAppTokenCacheProvider, MsalAppDistributedTokenCacheProvider>();
32+
services.AddSingleton<IMsalTokenCacheProvider, MsalDistributedTokenCacheAdapter>();
3333
return services;
3434
}
3535

@@ -42,7 +42,7 @@ public static IServiceCollection AddDistributedUserTokenCache(
4242
{
4343
services.AddDistributedMemoryCache();
4444
services.AddHttpContextAccessor();
45-
services.AddSingleton<IMsalUserTokenCacheProvider, MsalPerUserDistributedTokenCacheProvider>();
45+
services.AddSingleton<IMsalTokenCacheProvider, MsalDistributedTokenCacheAdapter>();
4646
return services;
4747
}
4848
}

Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalAppDistributedTokenCacheProvider.cs

Lines changed: 0 additions & 36 deletions
This file was deleted.

Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalPerUserDistributedTokenCacheProvider.cs

Lines changed: 0 additions & 37 deletions
This file was deleted.

Microsoft.Identity.Web/TokenCacheProviders/IMSALUserTokenCacheProvider.cs

Lines changed: 0 additions & 16 deletions
This file was deleted.

Microsoft.Identity.Web/TokenCacheProviders/IMsalAppTokenCacheProvider.cs

Lines changed: 0 additions & 16 deletions
This file was deleted.

Microsoft.Identity.Web/TokenCacheProviders/IMsalTokenCacheProvider .cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public interface IMsalTokenCacheProvider
1818
/// <param name="isAppTokenCache">Is the token cache an App token cache or
1919
/// a user token cache</param>
2020
/// <returns></returns>
21-
Task InitializeAsync(ITokenCache tokenCache, bool isAppTokenCache);
21+
Task InitializeAsync(ITokenCache tokenCache);
2222

2323
/// <summary>
2424
/// Clear the cache

Microsoft.Identity.Web/TokenCacheProviders/InMemory/InMemoryTokenCacheProviderExtension.cs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,10 @@ public static class InMemoryTokenCacheProviderExtension
1616
/// <returns></returns>
1717
public static IServiceCollection AddInMemoryTokenCaches(
1818
this IServiceCollection services)
19-
{
20-
AddInMemoryAppTokenCache(services);
21-
AddInMemoryPerUserTokenCache(services);
22-
return services;
23-
}
24-
25-
/// <summary>Adds the in-memory based application token cache to the service collection.</summary>
26-
/// <param name="services">The services collection to add to.</param>
27-
/// <param name="cacheOptions">The MSALMemoryTokenCacheOptions allows the caller to set the token cache expiration</param>
28-
public static IServiceCollection AddInMemoryAppTokenCache(
29-
this IServiceCollection services)
30-
{
31-
services.AddMemoryCache();
32-
services.AddSingleton<IMsalAppTokenCacheProvider, MsalAppMemoryTokenCacheProvider>();
33-
return services;
34-
}
35-
36-
/// <summary>Adds the in-memory based per user token cache to the service collection.</summary>
37-
/// <param name="services">The services collection to add to.</param>
38-
/// <param name="cacheOptions">The MSALMemoryTokenCacheOptions allows the caller to set the token cache expiration</param>
39-
/// <returns></returns>
40-
public static IServiceCollection AddInMemoryPerUserTokenCache(
41-
this IServiceCollection services)
4219
{
4320
services.AddMemoryCache();
4421
services.AddHttpContextAccessor();
45-
services.AddSingleton<IMsalUserTokenCacheProvider, MsalPerUserMemoryTokenCacheProvider>();
22+
services.AddSingleton<IMsalTokenCacheProvider, MsalMemoryTokenCacheProvider>();
4623
return services;
4724
}
4825
}

Microsoft.Identity.Web/TokenCacheProviders/InMemory/MsalAppMemoryTokenCacheProvider.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)