Skip to content

Commit 37f9eda

Browse files
Initial sample commit (#110)
1 parent fb95ec6 commit 37f9eda

37 files changed

+1404
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<InvariantGlobalization>true</InvariantGlobalization>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
12+
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0-rc.2.23480.2" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0-rc.2.23480.1" />
14+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0-rc.2.23480.2" />
15+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@Backend_HostAddress = http://localhost:5266
2+
3+
GET {{Backend_HostAddress}}/weatherforecast/
4+
Accept: application/json
5+
6+
###
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Microsoft.AspNetCore.Identity;
2+
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore;
4+
using System.Security.Claims;
5+
6+
var builder = WebApplication.CreateBuilder(args);
7+
8+
// cookie authentication
9+
builder.Services.AddAuthentication(IdentityConstants.ApplicationScheme).AddIdentityCookies();
10+
11+
// configure authorization
12+
builder.Services.AddAuthorizationBuilder();
13+
14+
// add the database (in memory for the sample)
15+
builder.Services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase("AppDb"));
16+
17+
// add identity and opt-in to endpoints
18+
builder.Services.AddIdentityCore<MyUser>()
19+
.AddEntityFrameworkStores<AppDbContext>()
20+
.AddApiEndpoints();
21+
22+
// add CORS policy for Wasm client
23+
builder.Services.AddCors(
24+
options => options.AddPolicy(
25+
"wasm",
26+
policy => policy.WithOrigins([builder.Configuration["BackendUrl"], builder.Configuration["FrontendUrl"]])
27+
.AllowAnyMethod()
28+
.SetIsOriginAllowed(pol => true)
29+
.AllowAnyHeader()
30+
.AllowCredentials()));
31+
32+
// Add services to the container.
33+
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
34+
builder.Services.AddEndpointsApiExplorer();
35+
builder.Services.AddSwaggerGen();
36+
37+
var app = builder.Build();
38+
39+
// create routes for the identity endpoints
40+
app.MapIdentityApi<MyUser>();
41+
42+
// provide an end point to clear the cookie for logout
43+
app.MapPost("/Logout", async (
44+
ClaimsPrincipal user,
45+
SignInManager<MyUser> signInManager) =>
46+
{
47+
await signInManager.SignOutAsync();
48+
return TypedResults.Ok();
49+
});
50+
51+
// activate the CORS policy
52+
app.UseCors("wasm");
53+
54+
// Configure the HTTP request pipeline.
55+
if (app.Environment.IsDevelopment())
56+
{
57+
app.UseSwagger();
58+
app.UseSwaggerUI();
59+
}
60+
61+
app.UseHttpsRedirection();
62+
app.Run();
63+
64+
// identity user
65+
class MyUser : IdentityUser { }
66+
67+
// identity database
68+
class AppDbContext(DbContextOptions<AppDbContext> options) : IdentityDbContext<MyUser>(options)
69+
{
70+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"iisSettings": {
4+
"windowsAuthentication": false,
5+
"anonymousAuthentication": true,
6+
"iisExpress": {
7+
"applicationUrl": "http://localhost:27123",
8+
"sslPort": 44394
9+
}
10+
},
11+
"profiles": {
12+
"http": {
13+
"commandName": "Project",
14+
"dotnetRunMessages": true,
15+
"launchBrowser": true,
16+
"launchUrl": "swagger",
17+
"applicationUrl": "http://localhost:5266",
18+
"environmentVariables": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
}
21+
},
22+
"https": {
23+
"commandName": "Project",
24+
"dotnetRunMessages": true,
25+
"launchBrowser": true,
26+
"launchUrl": "swagger",
27+
"applicationUrl": "https://localhost:7211;http://localhost:5266",
28+
"environmentVariables": {
29+
"ASPNETCORE_ENVIRONMENT": "Development"
30+
}
31+
},
32+
"IIS Express": {
33+
"commandName": "IISExpress",
34+
"launchBrowser": true,
35+
"launchUrl": "swagger",
36+
"environmentVariables": {
37+
"ASPNETCORE_ENVIRONMENT": "Development"
38+
}
39+
}
40+
}
41+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*",
9+
"BackendUrl": "https://localhost:7211",
10+
"FrontendUrl": "https://localhost:7171"
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.0-rtm.23502.22" />
11+
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0-rc.2.23479.6" />
12+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0-rtm.23502.22" />
13+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0-rtm.23502.22" PrivateAssets="all" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<CascadingAuthenticationState>
2+
<Router AppAssembly="@typeof(App).Assembly">
3+
<Found Context="routeData">
4+
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
5+
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
6+
</Found>
7+
<NotFound>
8+
<PageTitle>Not found</PageTitle>
9+
<LayoutView Layout="@typeof(MainLayout)">
10+
<p role="alert">Sorry, there's nothing at this address.</p>
11+
</LayoutView>
12+
</NotFound>
13+
</Router>
14+
</CascadingAuthenticationState>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
@page "/login"
2+
@using BlazorWasmAuth.Identity
3+
@inject IAccountManagement Acct
4+
5+
<AuthorizeView>
6+
<Authorized>
7+
<div class="alert alert-success">You are logged in as @context.User.Identity?.Name.</div>
8+
</Authorized>
9+
<NotAuthorized>
10+
<h1>Login</h1>
11+
@if (errors)
12+
{
13+
@foreach (var error in errorList)
14+
{
15+
<div class="alert alert-danger">@error</div>
16+
}
17+
}
18+
<div class="flex-outer">
19+
<div>
20+
<label for="email">
21+
Email:
22+
</label>
23+
<input required id="email" name="emailInput" placeholder="Enter your email address" type="email" @bind-value="email" />
24+
</div>
25+
26+
<div>
27+
<label for="password">
28+
Password:
29+
</label>
30+
<input required id="password" name="passwordInput" placeholder="Enter your password" type="password" @bind-value="password" />
31+
</div>
32+
<div>
33+
<button @onclick="DoLoginAsync">Login</button>
34+
</div>
35+
</div>
36+
</NotAuthorized>
37+
</AuthorizeView>
38+
39+
@code {
40+
private bool success, errors;
41+
private string email = string.Empty;
42+
private string password = string.Empty;
43+
private string[] errorList = [];
44+
45+
public async Task DoLoginAsync()
46+
{
47+
success = errors = false;
48+
errorList = [];
49+
50+
if (string.IsNullOrWhiteSpace(email))
51+
{
52+
errors = true;
53+
errorList = ["Email is required."];
54+
return;
55+
}
56+
57+
if (string.IsNullOrWhiteSpace(password))
58+
{
59+
errors = true;
60+
errorList = ["Password is required."];
61+
return;
62+
}
63+
64+
var result = await Acct.LoginAsync(email!, password!);
65+
66+
if (result.Succeeded)
67+
{
68+
success = true;
69+
email = password = string.Empty;
70+
}
71+
else
72+
{
73+
errors = true;
74+
errorList = result.ErrorList;
75+
}
76+
}
77+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@page "/logout"
2+
@using BlazorWasmAuth.Identity
3+
@inject IAccountManagement AcctMgmt
4+
5+
<AuthorizeView @ref="authView">
6+
<Authorized>
7+
<div class="alert alert-info">Logging you out...</div>
8+
</Authorized>
9+
<NotAuthorized><div class="alert alert-success">You are logged out. <a href="/login">Log in.</a></div></NotAuthorized>
10+
</AuthorizeView>
11+
12+
@code {
13+
private AuthorizeView? authView;
14+
15+
protected override async Task OnInitializedAsync()
16+
{
17+
if (await AcctMgmt.CheckAuthenticatedAsync())
18+
{
19+
await AcctMgmt.LogoutAsync();
20+
}
21+
await base.OnInitializedAsync();
22+
}
23+
}

0 commit comments

Comments
 (0)