Skip to content

Commit b40d429

Browse files
committed
c3s2 ready
1 parent 5419ca0 commit b40d429

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2464
-55
lines changed

1-Authentication/2-sign-in-b2c/SPA/src/app/app.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { HomeComponent } from './home/home.component';
1414
import { GuardedComponent } from './guarded/guarded.component';
1515

1616
import { HttpClientModule } from '@angular/common/http';
17-
import { IPublicClientApplication, PublicClientApplication, InteractionType, BrowserCacheLocation, LogLevel } from '@azure/msal-browser';
17+
import { IPublicClientApplication, PublicClientApplication, InteractionType } from '@azure/msal-browser';
1818
import { MsalGuard, MsalBroadcastService, MsalModule, MsalService, MSAL_GUARD_CONFIG, MSAL_INSTANCE, MsalGuardConfiguration, MsalRedirectComponent } from '@azure/msal-angular';
1919

2020
import { msalConfig } from './auth-config';

3-Authorization-II/1-call-api/README-incremental.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ This sample demonstrates an Angular single-page application (SPA) calling a ASP.
1919

2020
## Scenario
2121

22-
- The client Angular SPA uses [MSAL Angular](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular) to sign-in a user.
23-
- The app then obtains an [access token](https://docs.microsoft.com/azure/active-directory/develop/access-tokens) from **Azure AD** for the signed-in user.
24-
- The **access token** is then used to authorize the call to the service .NET Core web API.
25-
- .NET Core web API uses *M.I.W* to protect its endpoint and accept authorized calls.
22+
1. The client Angular SPA uses **MSAL Angular** to sign-in and obtain a JWT access token from **Azure AD**.
23+
2. The access token is used as a bearer token to authorize the user to call the .NET Core web API protected by **Azure AD**.
2624

2725
![Topology](./ReadmeFiles/topology.png)
2826

@@ -43,7 +41,7 @@ This sample demonstrates an Angular single-page application (SPA) calling a ASP.
4341

4442
```console
4543
cd ms-identity-javascript-angular-tutorial
46-
cd 3-Authorization-II/API
44+
cd 3-Authorization-II/1-call-api/API
4745
dotnet restore
4846
```
4947

@@ -154,7 +152,7 @@ Open the project in your IDE to configure the code.
154152
1. Open the `SPA\src\app\auth-config.ts` file.
155153
1. Find the key `Enter_the_Application_Id_Here` and replace the existing value with the application ID (clientId) of `msal-angular-spa` app copied from the Azure Portal.
156154
1. Find the key `Enter_the_Tenant_Info_Here` and replace the existing value with your Azure AD tenant ID.
157-
1. Find the key `Enter_the_Web_Api_Scope_here` and replace the existing value with *scope* you created earlier `api://{clientId}/access_as_user`.
155+
1. Find the key `Enter_the_Web_Api_Scope_here` and replace the existing value with *scope* you created earlier e.g. `api://{clientId}/access_as_user`.
158156

159157
## Run the sample
160158

3-Authorization-II/1-call-api/README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ This sample demonstrates an Angular single-page application (SPA) calling a ASP.
1919

2020
## Scenario
2121

22-
- The client Angular SPA uses [MSAL Angular](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular) to sign-in a user.
23-
- The app then obtains an [access token](https://docs.microsoft.com/azure/active-directory/develop/access-tokens) from **Azure AD** for the signed-in user.
24-
- The **access token** is then used to authorize the call to the service .NET Core web API.
25-
- .NET Core web API uses *M.I.W* to protect its endpoint and accept authorized calls.
22+
1. The client Angular SPA uses **MSAL Angular** to sign-in and obtain a JWT access token from **Azure AD**.
23+
2. The access token is used as a bearer token to authorize the user to call the .NET Core web API protected by **Azure AD**.
2624

2725
![Topology](./ReadmeFiles/topology.png)
2826

@@ -59,7 +57,7 @@ or download and extract the repository .zip file.
5957

6058
```console
6159
cd ms-identity-javascript-angular-tutorial
62-
cd 3-Authorization-II/API
60+
cd 3-Authorization-II/1-call-api/API
6361
dotnet restore
6462
```
6563

@@ -176,7 +174,7 @@ Open the project in your IDE to configure the code.
176174
1. Open the `SPA\src\app\auth-config.ts` file.
177175
1. Find the key `Enter_the_Application_Id_Here` and replace the existing value with the application ID (clientId) of `msal-angular-spa` app copied from the Azure Portal.
178176
1. Find the key `Enter_the_Tenant_Info_Here` and replace the existing value with your Azure AD tenant ID.
179-
1. Find the key `Enter_the_Web_Api_Scope_here` and replace the existing value with *scope* you created earlier `api://{clientId}/access_as_user`.
177+
1. Find the key `Enter_the_Web_Api_Scope_here` and replace the existing value with *scope* you created earlier e.g. `api://{clientId}/access_as_user`.
180178

181179
## Run the sample
182180

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Http;
6+
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.AspNetCore.Authorization;
8+
using Microsoft.EntityFrameworkCore;
9+
using TodoListAPI.Models;
10+
using System.Security.Claims;
11+
using Microsoft.Identity.Web.Resource;
12+
13+
namespace TodoListAPI.Controllers
14+
{
15+
[Authorize]
16+
[Route("api/[controller]")]
17+
[ApiController]
18+
public class TodoListController : ControllerBase
19+
{
20+
// The Web API will only accept tokens 1) for users, and
21+
// 2) having the access_as_user scope for this API
22+
static readonly string[] scopeRequiredByApi = new string[] { "demo.read" };
23+
24+
private readonly TodoContext _context;
25+
26+
public TodoListController(TodoContext context)
27+
{
28+
_context = context;
29+
}
30+
31+
// GET: api/TodoItems
32+
[HttpGet]
33+
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
34+
{
35+
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
36+
string owner = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
37+
return await _context.TodoItems.Where(item => item.Owner == owner).ToListAsync();
38+
}
39+
40+
// GET: api/TodoItems/5
41+
[HttpGet("{id}")]
42+
public async Task<ActionResult<TodoItem>> GetTodoItem(int id)
43+
{
44+
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
45+
46+
var todoItem = await _context.TodoItems.FindAsync(id);
47+
48+
if (todoItem == null)
49+
{
50+
return NotFound();
51+
}
52+
53+
return todoItem;
54+
}
55+
56+
// PUT: api/TodoItems/5
57+
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
58+
// more details see https://aka.ms/RazorPagesCRUD.
59+
[HttpPut("{id}")]
60+
public async Task<IActionResult> PutTodoItem(int id, TodoItem todoItem)
61+
{
62+
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
63+
64+
if (id != todoItem.Id)
65+
{
66+
return BadRequest();
67+
}
68+
69+
_context.Entry(todoItem).State = EntityState.Modified;
70+
71+
try
72+
{
73+
await _context.SaveChangesAsync();
74+
}
75+
catch (DbUpdateConcurrencyException)
76+
{
77+
if (!TodoItemExists(id))
78+
{
79+
return NotFound();
80+
}
81+
else
82+
{
83+
throw;
84+
}
85+
}
86+
87+
return NoContent();
88+
}
89+
90+
// POST: api/TodoItems
91+
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
92+
// more details see https://aka.ms/RazorPagesCRUD.
93+
[HttpPost]
94+
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
95+
{
96+
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
97+
string owner = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
98+
todoItem.Owner = owner;
99+
todoItem.Status = false;
100+
101+
_context.TodoItems.Add(todoItem);
102+
await _context.SaveChangesAsync();
103+
104+
return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
105+
}
106+
107+
// DELETE: api/TodoItems/5
108+
[HttpDelete("{id}")]
109+
public async Task<ActionResult<TodoItem>> DeleteTodoItem(int id)
110+
{
111+
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
112+
113+
var todoItem = await _context.TodoItems.FindAsync(id);
114+
if (todoItem == null)
115+
{
116+
return NotFound();
117+
}
118+
119+
_context.TodoItems.Remove(todoItem);
120+
await _context.SaveChangesAsync();
121+
122+
return todoItem;
123+
}
124+
125+
private bool TodoItemExists(int id)
126+
{
127+
return _context.TodoItems.Any(e => e.Id == id);
128+
}
129+
}
130+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace TodoListAPI.Models
4+
{
5+
public class TodoContext : DbContext
6+
{
7+
public TodoContext(DbContextOptions<TodoContext> options)
8+
: base(options)
9+
{
10+
11+
}
12+
13+
public DbSet<TodoItem> TodoItems { get; set; }
14+
}
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.ComponentModel.DataAnnotations;
5+
using System.ComponentModel.DataAnnotations.Schema;
6+
7+
namespace TodoListAPI.Models
8+
{
9+
public class TodoItem
10+
{
11+
[Key]
12+
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
13+
public int Id { get; set; }
14+
public string Owner { get; set; }
15+
public string Description { get; set; }
16+
public bool Status { get; set; }
17+
}
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.Extensions.Hosting;
4+
5+
namespace TodoListAPI
6+
{
7+
public class Program
8+
{
9+
public static void Main(string[] args)
10+
{
11+
CreateHostBuilder(args).Build().Run();
12+
}
13+
14+
public static IHostBuilder CreateHostBuilder(string[] args) =>
15+
Host.CreateDefaultBuilder(args)
16+
.ConfigureWebHostDefaults(webBuilder =>
17+
{
18+
webBuilder.UseStartup<Startup>();
19+
});
20+
}
21+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"iisSettings": {
4+
"windowsAuthentication": false,
5+
"anonymousAuthentication": true,
6+
"iisExpress": {
7+
"applicationUrl": "https://localhost:44351",
8+
"sslPort": 44351
9+
}
10+
},
11+
"profiles": {
12+
"IIS Express": {
13+
"commandName": "IISExpress",
14+
"launchBrowser": true,
15+
"launchUrl": "https://localhost:44351/api/todolist",
16+
"environmentVariables": {
17+
"ASPNETCORE_ENVIRONMENT": "Development"
18+
}
19+
},
20+
"TodoListAPI": {
21+
"commandName": "Project",
22+
"launchBrowser": true,
23+
"environmentVariables": {
24+
"ASPNETCORE_ENVIRONMENT": "Development"
25+
},
26+
"applicationUrl": "https://localhost:44351/",
27+
"sslPort": 44351
28+
}
29+
}
30+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
2+
using Microsoft.AspNetCore.Builder;
3+
using Microsoft.AspNetCore.Hosting;
4+
using Microsoft.Extensions.Hosting;
5+
using Microsoft.Extensions.Configuration;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.EntityFrameworkCore;
8+
using Microsoft.Identity.Web;
9+
using TodoListAPI.Models;
10+
using Microsoft.AspNetCore.Authentication.JwtBearer;
11+
12+
namespace TodoListAPI
13+
{
14+
public class Startup
15+
{
16+
public Startup(IConfiguration configuration)
17+
{
18+
Configuration = configuration;
19+
}
20+
21+
public IConfiguration Configuration { get; }
22+
23+
// This method gets called by the runtime. Use this method to add services to the container.
24+
public void ConfigureServices(IServiceCollection services)
25+
{
26+
27+
// Adds Microsoft Identity platform (AAD v2.0) support to protect this Api
28+
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
29+
.AddMicrosoftIdentityWebApi(options =>
30+
{
31+
Configuration.Bind("AzureAdB2C", options);
32+
33+
options.TokenValidationParameters.NameClaimType = "name";
34+
},
35+
options => { Configuration.Bind("AzureAdB2C", options); });
36+
37+
// Creating policies that wraps the authorization requirements
38+
services.AddAuthorization();
39+
40+
services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList"));
41+
42+
services.AddControllers();
43+
44+
// Allowing CORS for all domains and methods for the purpose of the sample
45+
// In production, modify this with the actual domains you want to allow
46+
services.AddCors(o => o.AddPolicy("default", builder =>
47+
{
48+
builder.AllowAnyOrigin()
49+
.AllowAnyMethod()
50+
.AllowAnyHeader();
51+
}));
52+
}
53+
54+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
55+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
56+
{
57+
if (env.IsDevelopment())
58+
{
59+
// Since IdentityModel version 5.2.1 (or since Microsoft.AspNetCore.Authentication.JwtBearer version 2.2.0),
60+
// Personal Identifiable Information is not written to the logs by default, to be compliant with GDPR.
61+
// For debugging/development purposes, one can enable additional detail in exceptions by setting IdentityModelEventSource.ShowPII to true.
62+
// Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
63+
app.UseDeveloperExceptionPage();
64+
}
65+
else
66+
{
67+
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
68+
app.UseHsts();
69+
}
70+
71+
app.UseCors("default");
72+
app.UseHttpsRedirection();
73+
app.UseRouting();
74+
app.UseAuthentication();
75+
app.UseAuthorization();
76+
app.UseEndpoints(endpoints =>
77+
{
78+
endpoints.MapControllers();
79+
});
80+
}
81+
}
82+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<UserSecretsId>aspnet-TodoListAPI-BA938C29-8BAB-4664-A688-8FD54049C1C3</UserSecretsId>
6+
<WebProject_DirectoryAccessLevelKey>1</WebProject_DirectoryAccessLevelKey>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.9" />
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.9" />
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.9" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.9">
14+
<PrivateAssets>all</PrivateAssets>
15+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
16+
</PackageReference>
17+
<PackageReference Include="Microsoft.Identity.Web" Version="1.8.0" />
18+
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.4" />
19+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.9" Condition="'$(Configuration)' == 'Debug'" />
20+
</ItemGroup>
21+
22+
</Project>

0 commit comments

Comments
 (0)