diff --git a/.gitignore b/.gitignore index 785fcf0..c1aab2e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ msbuild.wrn .vscode/ .vs/ .idea/ +appsettings.development.json # Cache *.swp diff --git a/AdvancedSystems.Backend/AdvancedSystems.Backend.csproj b/AdvancedSystems.Backend/AdvancedSystems.Backend.csproj index b64ac70..5b3ce3e 100644 --- a/AdvancedSystems.Backend/AdvancedSystems.Backend.csproj +++ b/AdvancedSystems.Backend/AdvancedSystems.Backend.csproj @@ -13,6 +13,7 @@ + diff --git a/AdvancedSystems.Backend/DependencyInjection/ServiceCollectionExtensions.cs b/AdvancedSystems.Backend/DependencyInjection/ServiceCollectionExtensions.cs index 9195562..da26990 100644 --- a/AdvancedSystems.Backend/DependencyInjection/ServiceCollectionExtensions.cs +++ b/AdvancedSystems.Backend/DependencyInjection/ServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using AdvancedSystems.Backend.Core.Validators; using AdvancedSystems.Backend.Interfaces; +using AdvancedSystems.Backend.Models; using AdvancedSystems.Backend.Models.Settings; using AdvancedSystems.Backend.Services; using AdvancedSystems.Backend.Services.HealthChecks; @@ -12,6 +13,7 @@ using Asp.Versioning; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Http; @@ -21,6 +23,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; using Swashbuckle.AspNetCore.SwaggerGen; @@ -86,9 +89,53 @@ public static IServiceCollection AddCachingService(this IServiceCollection servi } #endregion - + + #region Authentication and Authorization + + public static IServiceCollection AddJwtAuth(this IServiceCollection services) + { + var authBuilder = services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }); + + authBuilder.AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + // TODO: configure token validation parameters properly + IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("secret")), + ValidateIssuerSigningKey = true, + ValidateLifetime = true, + ValidIssuer = "issuer", + ValidAudience = "audience", + ValidateIssuer = true, + ValidateAudience = true, + }; + }); + + services.AddJwtPolicy(); + + return services; + } + + public static IServiceCollection AddJwtPolicy(this IServiceCollection services) + { + return services.AddAuthorization(options => + { + options.AddPolicy(Roles.Admin, policy => + { + policy.RequireClaim(CustomClaim.IsAdmin, "true").RequireAuthenticatedUser(); + }); + }); + } + + #endregion + #region Health Checks - + public static IServiceCollection AddBackendHealthChecks(this IServiceCollection services) { services.AddSingleton(); @@ -126,12 +173,16 @@ public static IServiceCollection AddBackendDocumentation(this IServiceCollection { var settings = configuration.GetRequiredSection(nameof(AppSettings)).Get(); - services.AddApiVersioning(option => { + var apiVersionBuilder = services.AddApiVersioning(option => { option.DefaultApiVersion = new ApiVersion(settings!.DefaultApiVersion); option.AssumeDefaultVersionWhenUnspecified = true; option.ReportApiVersions = true; option.ApiVersionReader = new MediaTypeApiVersionReader("api-version"); - }).AddMvc().AddApiExplorer(); + }); + + apiVersionBuilder + .AddMvc() + .AddApiExplorer(); services.TryAdd(ServiceDescriptor.Transient, ConfigureSwaggerOptions>()); services.AddSwaggerGen(option => option.OperationFilter()); diff --git a/AdvancedSystems.Backend/DependencyInjection/Startup.cs b/AdvancedSystems.Backend/DependencyInjection/Startup.cs index 7e844bf..f0f12cf 100644 --- a/AdvancedSystems.Backend/DependencyInjection/Startup.cs +++ b/AdvancedSystems.Backend/DependencyInjection/Startup.cs @@ -54,6 +54,8 @@ public static IServiceCollection ConfigureServices(this IServiceCollection servi options.LowercaseUrls = true; }); + services.AddJwtAuth(); + services.AddControllers(); services.AddBackendHealthChecks(); @@ -85,6 +87,9 @@ public static void Configure(this WebApplication app, IHostEnvironment environme app.UseHsts(); } + app.UseAuthentication(); + app.UseAuthorization(); + app.UseHttpsRedirection(); app.UseStatusCodePages(); app.UseExceptionHandler(); diff --git a/AdvancedSystems.Backend/Models/CustomClaim.cs b/AdvancedSystems.Backend/Models/CustomClaim.cs new file mode 100644 index 0000000..e59ca1c --- /dev/null +++ b/AdvancedSystems.Backend/Models/CustomClaim.cs @@ -0,0 +1,6 @@ +namespace AdvancedSystems.Backend.Models; + +public static class CustomClaim +{ + public static readonly string IsAdmin = "is_admin"; +} diff --git a/AdvancedSystems.Backend/Models/Roles.cs b/AdvancedSystems.Backend/Models/Roles.cs new file mode 100644 index 0000000..00b0760 --- /dev/null +++ b/AdvancedSystems.Backend/Models/Roles.cs @@ -0,0 +1,6 @@ +namespace AdvancedSystems.Backend.Models; + +public static class Roles +{ + public static readonly string Admin = "Admin"; +} diff --git a/AdvancedSystems.Backend/appsettings.json b/AdvancedSystems.Backend/appsettings.json index 886f7f2..a398b8f 100644 --- a/AdvancedSystems.Backend/appsettings.json +++ b/AdvancedSystems.Backend/appsettings.json @@ -2,6 +2,11 @@ "AppSettings": { "DefaultApiVersion": 1.0 }, + "Jwt": { + "Key": "", + "Issuer": "", + "Audience": "" + }, "NLog": { "extensions": [ {