Skip to content

Commit 7e84309

Browse files
committed
First commit !
1 parent 5639eff commit 7e84309

16 files changed

+320
-0
lines changed

.editorconfig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
root = true
2+
3+
# All files
4+
[*]
5+
indent_style = space
6+
7+
# C# files
8+
[*.cs]
9+
10+
# Indentation and spacing
11+
indent_size = 4
12+
tab_width = 4
13+
14+
# New line preferences
15+
end_of_line = crlf
16+
insert_final_newline = false
17+
18+
# Remove useless namespaces
19+
dotnet_diagnostic.IDE0005.severity = error
20+
dotnet_diagnostic.ASP0025.severity = none
21+

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,3 +416,7 @@ FodyWeavers.xsd
416416
*.msix
417417
*.msm
418418
*.msp
419+
420+
# JetBrains Rider
421+
*.sln.iml
422+
.idea/*

Directory.Build.props

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project>
2+
<PropertyGroup>
3+
<Deterministic>true</Deterministic>
4+
<EnableNETAnalyzers>true</EnableNETAnalyzers>
5+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
6+
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
7+
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
8+
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
9+
<NoWarn>$(NoWarn);</NoWarn>
10+
</PropertyGroup>
11+
</Project>

Directory.Packages.props

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.8" />
8+
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.3" />
9+
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.3" />
10+
</ItemGroup>
11+
</Project>

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,29 @@
11
# UserJwtsDemo
2+
```
23
Using dotnet user-jwts to simplify working with jwt tokens
4+
```
5+
6+
> In this repo, i m using a [dotnet user-jwts](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/jwt-authn?view=aspnetcore-9.0&tabs=windows) to illustrate how jwt tokens can be generated and applied in .net web api development.
7+
>
8+
> This repo contains three endpoints, each secured with different role requirements. To access an endpoint, you must generate a JWT token that includes the appropriate role.
9+
>
10+
11+
### Endpoints
12+
>
13+
>:one: **`/user`**
14+
>```bash
15+
> dotnet user-jwts create -p .\src\WebApi
16+
>```
17+
18+
> :two: **`/admin-user`**
19+
> ```bash
20+
> dotnet user-jwts create -p .\src\WebApi --role Admin
21+
> ```
22+
23+
> :three: **`/super-user`**
24+
> ```bash
25+
> dotnet user-jwts create -p .\src\WebApi --role Admin --role Manager
26+
> ```
27+
>
28+
29+
**`Tools`** : net 9.0

UserJwtsDemo.slnx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Solution>
2+
<Folder Name="/files/">
3+
<File Path=".editorconfig" />
4+
<File Path="Directory.Build.props" />
5+
<File Path="global.json" />
6+
<File Path="Directory.Packages.props" />
7+
<File Path=".gitignore" />
8+
<File Path="README.md" />
9+
</Folder>
10+
<Folder Name="/src/">
11+
<Project Path="src/WebApi/WebApi.csproj" />
12+
</Folder>
13+
</Solution>

global.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"sdk": {
3+
"version": "9.0.200",
4+
"rollForward": "latestMinor",
5+
"allowPrerelease": true
6+
}
7+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using Microsoft.AspNetCore.Authentication;
2+
using Microsoft.AspNetCore.Authentication.JwtBearer;
3+
using Microsoft.AspNetCore.OpenApi;
4+
using Microsoft.OpenApi.Models;
5+
6+
namespace WebApi;
7+
8+
public sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
9+
{
10+
private const string BearerSchemeName = "Bearer";
11+
private const string OpenApiBearerSchemeName = "bearer";
12+
13+
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
14+
{
15+
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
16+
if (authenticationSchemes.Any(x => x.Name == BearerSchemeName))
17+
{
18+
var requirements = new Dictionary<string, OpenApiSecurityScheme>
19+
{
20+
[JwtBearerDefaults.AuthenticationScheme] = new()
21+
{
22+
Scheme = OpenApiBearerSchemeName,
23+
Type = SecuritySchemeType.Http,
24+
In = ParameterLocation.Header
25+
}
26+
};
27+
document.Components ??= new OpenApiComponents();
28+
document.Components.SecuritySchemes = requirements;
29+
30+
document.SecurityRequirements ??= [];
31+
document.SecurityRequirements.Add(new OpenApiSecurityRequirement
32+
{
33+
[new OpenApiSecurityScheme
34+
{
35+
Reference = new OpenApiReference
36+
{
37+
Id = JwtBearerDefaults.AuthenticationScheme,
38+
Type = ReferenceType.SecurityScheme
39+
}
40+
}] = Array.Empty<string>()
41+
});
42+
}
43+
}
44+
}

src/WebApi/Constants.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace WebApi;
2+
3+
public static class Constants
4+
{
5+
public static class Policies
6+
{
7+
public const string AdminOnly = "AdminOnly";
8+
public const string SuperUserOnly = "SuperUserOnly";
9+
}
10+
}

src/WebApi/Program.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using Microsoft.AspNetCore.Authentication.JwtBearer;
2+
using WebApi;
3+
4+
var builder = WebApplication.CreateBuilder(args);
5+
6+
builder.Services.AddOpenApi(options =>
7+
{
8+
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
9+
});
10+
11+
builder.Services
12+
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
13+
.AddJwtBearer();
14+
15+
builder.Services.AddAuthorization(options =>
16+
{
17+
options.AddPolicy(Constants.Policies.AdminOnly, policy =>
18+
policy.RequireRole("Admin"));
19+
20+
options.AddPolicy(Constants.Policies.SuperUserOnly, policy =>
21+
policy.RequireRole("Admin").RequireRole("Manager"));
22+
});
23+
24+
var app = builder.Build();
25+
26+
if (app.Environment.IsDevelopment())
27+
{
28+
app.MapOpenApi();
29+
app.UseSwaggerUI(options =>
30+
{
31+
options.SwaggerEndpoint("/openapi/v1.json", "v1");
32+
});
33+
}
34+
35+
app.UseHttpsRedirection();
36+
37+
app.UseAuthentication();
38+
39+
app.UseAuthorization();
40+
41+
app
42+
.MapGet("/user", (HttpContext context) =>
43+
{
44+
var user = User.Create(context);
45+
return Results.Ok(user);
46+
})
47+
.RequireAuthorization();
48+
49+
app
50+
.MapGet("/admin-user", (HttpContext context) =>
51+
{
52+
var adminUser = User.Create(context);
53+
return Results.Ok(adminUser);
54+
})
55+
.RequireAuthorization(Constants.Policies.AdminOnly);
56+
57+
app
58+
.MapGet("/super-user", (HttpContext context) =>
59+
{
60+
var superUser = User.Create(context);
61+
return Results.Ok(superUser);
62+
})
63+
.RequireAuthorization(Constants.Policies.SuperUserOnly);
64+
65+
await app.RunAsync();

0 commit comments

Comments
 (0)