Skip to content

Commit 0888323

Browse files
committed
up
1 parent 7edd47a commit 0888323

19 files changed

Lines changed: 672 additions & 110 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 32 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,48 @@
11
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
22
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
33
{
4-
"name": "C# (.NET)",
4+
"name": "Aspire",
55
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6-
"image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm",
7-
8-
// Features to add to the dev container. More info: https://containers.dev/features.
6+
"image": "mcr.microsoft.com/devcontainers/dotnet:dev-10.0-noble",
97
"features": {
10-
"ghcr.io/elanhasson/devcontainer-features/dotnet-aspire-daily:1": {},
11-
"ghcr.io/devcontainers/features/dotnet:2": {},
12-
"ghcr.io/devcontainers/features/common-utils:2": {},
8+
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
9+
"ghcr.io/devcontainers/features/powershell:1": {},
1310
"ghcr.io/devcontainers/features/node:1": {},
14-
"ghcr.io/devcontainers/features/git:1": {},
15-
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
11+
"ghcr.io/devcontainers/features/python:1": {},
12+
"ghcr.io/devcontainers-extra/features/uv:1": {}
1613
},
14+
15+
// "hostRequirements": {
16+
// "cpus": 8,
17+
// "memory": "32gb",
18+
// "storage": "64gb"
19+
// },
20+
21+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
22+
// "forwardPorts": [5000, 5001],
23+
// "portsAttributes": {
24+
// "5001": {
25+
// "protocol": "https"
26+
// }
27+
// }
28+
29+
// Use 'postCreateCommand' to run commands after the container is created.
30+
// "postCreateCommand": "dotnet restore",
31+
"onCreateCommand": "curl -sSL https://aspire.dev/install.sh | bash",
32+
"postStartCommand": "dotnet dev-certs https --trust",
1733
"customizations": {
1834
"vscode": {
1935
"extensions": [
2036
"ms-dotnettools.csdevkit",
21-
"ms-dotnettools.vscodeintellicode-csharp",
22-
"ms-dotnettools.csharp",
23-
"ms-dotnettools.vscode-dotnet-runtime",
24-
"streetsidesoftware.code-spell-checker",
25-
"esbenp.prettier-vscode",
26-
"EditorConfig.EditorConfig"
37+
"ms-vscode.vscode-typescript-next",
38+
"GitHub.copilot-chat",
39+
"GitHub.copilot"
2740
]
2841
}
29-
},
30-
31-
// Use 'forwardPorts' to make a list of ports inside the container available locally.
32-
"forwardPorts": [17290, 17290],
33-
"portsAttributes": {
34-
"5001": {
35-
"label": "apiservice"
36-
//"protocol": "https"
37-
}
38-
},
39-
40-
// 1. Export it locally using this command:
41-
// * Windows PowerShell:
42-
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "$env:USERPROFILE/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
43-
// * macOS/Linux terminal:
44-
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "${HOME}/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
45-
//
46-
// 2. Uncomment these 'remoteEnv' lines:
47-
"remoteEnv": {
48-
"ASPNETCORE_Kestrel__Certificates__Default__Password": "P@ssword",
49-
"ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx"
50-
},
51-
//
52-
// 3. Do one of the following depending on your scenario:
53-
// * When using GitHub Codespaces and/or Remote - Containers:
54-
// 1. Start the container
55-
// 2. Drag ~/.aspnet/https/aspnetapp.pfx into the root of the file explorer
56-
// 3. Open a terminal in VS Code and run "mkdir -p /home/vscode/.aspnet/https && mv aspnetapp.pfx /home/vscode/.aspnet/https"
57-
//
58-
// * If only using Remote - Containers with a local container, uncomment this line instead:
59-
"mounts": [
60-
"source=${env:HOME}${env:USERPROFILE}/.aspnet/https,target=/home/vscode/.aspnet/https,type=bind"
61-
],
62-
63-
// Use 'postCreateCommand' to run commands after the container is created.
64-
"postCreateCommand": "",
42+
}
43+
// Configure tool-specific properties.
44+
// "customizations": {},
6545

6646
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
67-
"remoteUser": "root"
47+
// "remoteUser": "root"
6848
}

code/MicroCommerce.ApiService/Program.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Security.Claims;
2+
13
var builder = WebApplication.CreateBuilder(args);
24

35
// Add service defaults & Aspire client integrations.
@@ -6,16 +8,30 @@
68
// Add services to the container.
79
builder.Services.AddProblemDetails();
810

11+
// Add CORS for frontend
12+
builder.Services.AddCors(options =>
13+
{
14+
options.AddDefaultPolicy(policy =>
15+
{
16+
policy.WithOrigins("http://localhost:3000", "http://localhost:3001")
17+
.AllowAnyHeader()
18+
.AllowAnyMethod()
19+
.AllowCredentials();
20+
});
21+
});
22+
923
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
1024
builder.Services.AddOpenApi();
1125

1226
builder.Services.AddAuthentication()
1327
.AddKeycloakJwtBearer(
1428
serviceName: "keycloak",
15-
realm: "api",
29+
realm: "micro-commerce",
1630
options =>
1731
{
18-
options.Audience = "store.api";
32+
// Accept tokens issued to the nextjs-app client
33+
// The 'azp' (authorized party) claim will be 'nextjs-app'
34+
options.TokenValidationParameters.ValidateAudience = false;
1935

2036
// For development only - disable HTTPS metadata validation
2137
// In production, use explicit Authority configuration instead
@@ -30,6 +46,7 @@
3046

3147
// Configure the HTTP request pipeline.
3248
app.UseExceptionHandler();
49+
app.UseCors();
3350

3451
if (app.Environment.IsDevelopment())
3552
{
@@ -41,6 +58,22 @@
4158

4259
app.MapGet("/", () => "API service is running. Navigate to /weatherforecast to see sample data.");
4360

61+
// Protected endpoint - returns user info from JWT token
62+
app.MapGet("/me", (ClaimsPrincipal user) =>
63+
{
64+
var claims = user.Claims.Select(c => new { c.Type, c.Value }).ToList();
65+
return new
66+
{
67+
IsAuthenticated = user.Identity?.IsAuthenticated ?? false,
68+
Name = user.Identity?.Name,
69+
Email = user.FindFirst("email")?.Value,
70+
Subject = user.FindFirst("sub")?.Value,
71+
Claims = claims
72+
};
73+
})
74+
.WithName("GetCurrentUser")
75+
.RequireAuthorization();
76+
4477
app.MapGet("/weatherforecast", () =>
4578
{
4679
var forecast = Enumerable.Range(1, 5).Select(index =>

code/MicroCommerce.AppHost/AppHost.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
var keycloak = builder
44
.AddKeycloak("keycloak", 8101)
55
.WithDataVolume()
6-
.WithLifetime(ContainerLifetime.Persistent);
6+
.WithRealmImport("./Realms")
7+
.WithLifetime(ContainerLifetime.Persistent);
78

89
var apiService = builder.AddProject<Projects.MicroCommerce_ApiService>("apiservice")
910
.WithReference(keycloak)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
{
2+
"realm": "micro-commerce",
3+
"enabled": true,
4+
"sslRequired": "none",
5+
"registrationAllowed": true,
6+
"loginWithEmailAllowed": true,
7+
"duplicateEmailsAllowed": false,
8+
"resetPasswordAllowed": true,
9+
"editUsernameAllowed": false,
10+
"bruteForceProtected": true,
11+
"roles": {
12+
"realm": [
13+
{
14+
"name": "user",
15+
"description": "Regular user role"
16+
},
17+
{
18+
"name": "admin",
19+
"description": "Administrator role"
20+
}
21+
]
22+
},
23+
"clients": [
24+
{
25+
"clientId": "nextjs-app",
26+
"name": "Next.js Frontend",
27+
"description": "Next.js frontend application for MicroCommerce",
28+
"enabled": true,
29+
"clientAuthenticatorType": "client-secret",
30+
"secret": "nextjs-app-secret-change-in-production",
31+
"redirectUris": ["*"],
32+
"webOrigins": ["*"],
33+
"standardFlowEnabled": true,
34+
"implicitFlowEnabled": false,
35+
"directAccessGrantsEnabled": true,
36+
"serviceAccountsEnabled": false,
37+
"publicClient": false,
38+
"frontchannelLogout": true,
39+
"protocol": "openid-connect",
40+
"attributes": {
41+
"post.logout.redirect.uris": "+",
42+
"pkce.code.challenge.method": "S256"
43+
},
44+
"protocolMappers": [
45+
{
46+
"name": "store-api-audience",
47+
"protocol": "openid-connect",
48+
"protocolMapper": "oidc-audience-mapper",
49+
"consentRequired": false,
50+
"config": {
51+
"included.client.audience": "store.api",
52+
"id.token.claim": "false",
53+
"access.token.claim": "true"
54+
}
55+
}
56+
],
57+
"defaultClientScopes": [
58+
"web-origins",
59+
"acr",
60+
"profile",
61+
"roles",
62+
"email"
63+
],
64+
"optionalClientScopes": [
65+
"address",
66+
"phone",
67+
"offline_access",
68+
"microprofile-jwt"
69+
]
70+
},
71+
{
72+
"clientId": "store.api",
73+
"name": "Store API",
74+
"description": ".NET API Service for MicroCommerce",
75+
"enabled": true,
76+
"clientAuthenticatorType": "client-secret",
77+
"secret": "store-api-secret-change-in-production",
78+
"bearerOnly": true,
79+
"standardFlowEnabled": false,
80+
"implicitFlowEnabled": false,
81+
"directAccessGrantsEnabled": false,
82+
"serviceAccountsEnabled": false,
83+
"publicClient": false,
84+
"protocol": "openid-connect",
85+
"defaultClientScopes": ["web-origins", "acr", "profile", "roles", "email"]
86+
}
87+
],
88+
"users": [
89+
{
90+
"username": "testuser",
91+
"email": "testuser@example.com",
92+
"emailVerified": true,
93+
"enabled": true,
94+
"firstName": "Test",
95+
"lastName": "User",
96+
"credentials": [
97+
{
98+
"type": "password",
99+
"value": "testpassword",
100+
"temporary": false
101+
}
102+
],
103+
"realmRoles": ["user"]
104+
},
105+
{
106+
"username": "admin",
107+
"email": "admin@example.com",
108+
"emailVerified": true,
109+
"enabled": true,
110+
"firstName": "Admin",
111+
"lastName": "User",
112+
"credentials": [
113+
{
114+
"type": "password",
115+
"value": "adminpassword",
116+
"temporary": false
117+
}
118+
],
119+
"realmRoles": ["user", "admin"]
120+
}
121+
]
122+
}

code/MicroCommerce.Web/.env

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
AUTH_SECRET="GEppqsPV9n+/6QRZd3sLHr/V1zGpcBYnSL2VARgFam8=" # Added by `npx auth`. Read more: https://cli.authjs.dev
2+
3+
# Keycloak
4+
KEYCLOAK_CLIENT_ID=nextjs-app
5+
KEYCLOAK_CLIENT_SECRET=nextjs-app-secret-change-in-production
6+
KEYCLOAK_ISSUER=http://localhost:8101/realms/micro-commerce

code/MicroCommerce.Web/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ yarn-error.log*
3131
.pnpm-debug.log*
3232

3333
# env files (can opt-in for committing if needed)
34-
.env*
34+
#.env*
35+
.env.local
3536

3637
# vercel
3738
.vercel

0 commit comments

Comments
 (0)