Ver código fonte

Added protected endpoint with JWT authorization

Lukas Angerer 2 anos atrás
pai
commit
4edaad0070
4 arquivos alterados com 53 adições e 0 exclusões
  1. 1 0
      Passwordless.csproj
  2. 24 0
      Program.cs
  3. 8 0
      wwwroot/index.html
  4. 20 0
      wwwroot/main.js

+ 1 - 0
Passwordless.csproj

@@ -9,6 +9,7 @@
 
   <ItemGroup>
     <PackageReference Include="Fido2.AspNet" Version="3.0.1" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
     <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
   </ItemGroup>

+ 24 - 0
Program.cs

@@ -1,5 +1,7 @@
 using Fido2NetLib;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.IdentityModel.Tokens;
 using Passwordless;
 
 var builder = WebApplication.CreateBuilder(args);
@@ -15,6 +17,22 @@ builder.Services.AddFido2(options =>
     options.Origins = ["http://localhost:5172"];
     options.TimestampDriftTolerance = 300000;
 });
+builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+    .AddJwtBearer(options =>
+    {
+        options.RequireHttpsMetadata = false; // dev only!!!
+        options.Authority = "http://localhost:5172";
+        options.TokenValidationParameters = new TokenValidationParameters
+        {
+            ValidIssuer = "http://localhost:5172",
+            ValidAudience = "http://localhost:5172"
+        };
+    });
+
+builder.Services.AddAuthorization(authorizationOptions =>
+{
+    authorizationOptions.AddPolicy("MagicClaim", policyBuilder => policyBuilder.RequireClaim("permissions", "MagicClaim"));
+});
 builder.Services.AddMemoryCache();
 builder.Services.AddTransient<OptionsCache>();
 builder.Services.AddTransient<CredentialManager>();
@@ -30,6 +48,7 @@ if (app.Environment.IsDevelopment())
 
 app.UseStaticFiles();
 app.UseHttpsRedirection();
+app.UseAuthorization();
 
 app.MapGet("/buildCredentialOptions", ([FromQuery] string login, CredentialManager credMan) => 
         credMan.BuildCredentialOptions(login))
@@ -51,4 +70,9 @@ app.MapPost("/verifyCredential", async ([FromBody] AuthenticatorAssertionRawResp
     .WithName("VerifyCredential")
     .WithOpenApi();
 
+app.MapGet("/protected", () => "Success!").WithName("Protected").RequireAuthorization(policy =>
+{
+    policy.RequireClaim("MagicClaim");
+});
+
 app.Run();

+ 8 - 0
wwwroot/index.html

@@ -13,6 +13,14 @@
         <button id="register">Register</button>
         <button id="login">Login</button>
     </div>
+    <hr />
+    <div>
+        <pre><code id="userState">TEST</code></pre>
+        <div>
+            <button id="protected">Access Protected API</button>
+        </div>
+        <pre><code id="response">TEST</code></pre>
+    </div>
     <script src="main.js"></script>
 </body>
 </html>

+ 20 - 0
wwwroot/main.js

@@ -261,5 +261,25 @@ class Login {
     }
 }
 
+class ApiHandler {
+    constructor() {
+        document.getElementById('protected').addEventListener('click', this.access.bind(this));
+    }
+    
+    async access() {
+        const response = await fetch("/protected", {
+            method: 'GET',
+            headers: {
+                'Accept': 'application/json',
+                'Content-Type': 'application/json'
+            }
+        });
+        
+        console.log("/protected returned", response);
+        //response.status
+    }
+}
+
 window.registration = new Registration();
 window.login = new Login();
+window.api = new ApiHandler();