diff --git a/JwtStore.Api/Extensions/ServiceCollectionExtensions.cs b/JwtStore.Api/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 2e3bc86..0000000 --- a/JwtStore.Api/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using JwtStore.Api.Options; - -namespace JwtStore.Api.Extensions; - -public static class ServiceCollectionExtensions -{ - public static IServiceCollection AddConfigurations(this IServiceCollection services) - { - services.ConfigureOptions(); - - return services; - } -} diff --git a/JwtStore.Api/Options/SecretsOptionsSetup.cs b/JwtStore.Api/Options/SecretsOptionsSetup.cs deleted file mode 100644 index 4bf2e9e..0000000 --- a/JwtStore.Api/Options/SecretsOptionsSetup.cs +++ /dev/null @@ -1,17 +0,0 @@ -using JwtStore.Infrastructure.Options; -using Microsoft.Extensions.Options; - -namespace JwtStore.Api.Options; - -public class SecretsOptionsSetup : IConfigureOptions -{ - private const string Secrets = nameof(Secrets); - private readonly IConfiguration _configuration; - - public SecretsOptionsSetup(IConfiguration configuration) - => _configuration = configuration; - - public void Configure(SecretsOptions options) - => _configuration.GetSection(Secrets) - .Bind(options); -} diff --git a/JwtStore.Api/Program.cs b/JwtStore.Api/Program.cs index c1ad9ad..552ef87 100644 --- a/JwtStore.Api/Program.cs +++ b/JwtStore.Api/Program.cs @@ -1,4 +1,3 @@ -using JwtStore.Api.Extensions; using JwtStore.Infrastructure.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); diff --git a/JwtStore.Api/appsettings.Development.json b/JwtStore.Api/appsettings.Development.json index 1273d45..79c1495 100644 --- a/JwtStore.Api/appsettings.Development.json +++ b/JwtStore.Api/appsettings.Development.json @@ -2,9 +2,14 @@ "ConnectionStrings": { "DefaultConnection": "Server=localhost,1433;Database=jwt-store;User ID=sa;Password=1q2w3e4r@#$;Trusted_Connection=False; TrustServerCertificate=True;" }, + "Jwt": { + "PrivateKey": "", + "Audience": "", + "Issuer": "", + "ExpirationInMinutes": 0 + }, "Secrets": { "ApiKey": "", - "JwtPrivateKey": "", "PasswordSaltKey": "" }, "Logging": { diff --git a/JwtStore.Infrastructure/Authentication/JwtOptions.cs b/JwtStore.Infrastructure/Authentication/JwtOptions.cs new file mode 100644 index 0000000..8805112 --- /dev/null +++ b/JwtStore.Infrastructure/Authentication/JwtOptions.cs @@ -0,0 +1,14 @@ +namespace JwtStore.Infrastructure.Authentication; + +public sealed class JwtOptions +{ + public const string SectionName = "Jwt"; + + public string Audience { get; init; } = string.Empty; + + public string Issuer { get; init; } = string.Empty; + + public string PrivateKey { get; init; } = string.Empty; + + public int TokenExpirationInMinutes { get; init; } +} diff --git a/JwtStore.Infrastructure/Authentication/JwtOptionsSetup.cs b/JwtStore.Infrastructure/Authentication/JwtOptionsSetup.cs new file mode 100644 index 0000000..c0a5363 --- /dev/null +++ b/JwtStore.Infrastructure/Authentication/JwtOptionsSetup.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace JwtStore.Infrastructure.Authentication; + +public sealed class JwtOptionsSetup(IConfiguration configuration) + : IConfigureOptions +{ + private readonly IConfiguration _configuration = configuration; + + public void Configure(JwtOptions options) + => _configuration.GetSection(JwtOptions.SectionName) + .Bind(options); +} diff --git a/JwtStore.Infrastructure/Extensions/ServiceCollectionExtensions.cs b/JwtStore.Infrastructure/Extensions/ServiceCollectionExtensions.cs index f7a4d05..5ef6812 100644 --- a/JwtStore.Infrastructure/Extensions/ServiceCollectionExtensions.cs +++ b/JwtStore.Infrastructure/Extensions/ServiceCollectionExtensions.cs @@ -1,7 +1,13 @@ +using JwtStore.Infrastructure.Authentication; using JwtStore.Infrastructure.Data; +using JwtStore.Infrastructure.Options; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using System.Text; namespace JwtStore.Infrastructure.Extensions.DependencyInjection; @@ -9,6 +15,38 @@ public static class ServiceCollectionExtensions { private const string DefaultConnection = nameof(DefaultConnection); + public static IServiceCollection AddConfigurations(this IServiceCollection services) + { + services.ConfigureOptions(); + services.ConfigureOptions(); + + return services; + } + + public static IServiceCollection AddJwtAuthentication(this IServiceCollection services, IOptions options) + { + var jwtOptions = options.Value; + + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = jwtOptions.Issuer, + ValidAudience = jwtOptions.Audience, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.PrivateKey)) + }; + }); + + services.AddAuthorization(); + + return services; + } + public static IServiceCollection AddPersistence(this IServiceCollection services, IConfiguration configuration) { services.AddDbContext(options diff --git a/JwtStore.Infrastructure/JwtStore.Infrastructure.csproj b/JwtStore.Infrastructure/JwtStore.Infrastructure.csproj index 7030c79..17eba63 100644 --- a/JwtStore.Infrastructure/JwtStore.Infrastructure.csproj +++ b/JwtStore.Infrastructure/JwtStore.Infrastructure.csproj @@ -7,6 +7,7 @@ + diff --git a/JwtStore.Infrastructure/Options/SecretsOptions.cs b/JwtStore.Infrastructure/Options/SecretsOptions.cs index b6df4c0..2fc74bc 100644 --- a/JwtStore.Infrastructure/Options/SecretsOptions.cs +++ b/JwtStore.Infrastructure/Options/SecretsOptions.cs @@ -2,9 +2,9 @@ namespace JwtStore.Infrastructure.Options; public sealed class SecretsOptions { - public string ApiKey { get; init; } = string.Empty; + public const string SectionName = "Secrets"; - public string JwtPrivateKey { get; init; } = string.Empty; + public string ApiKey { get; init; } = string.Empty; public string PasswordSaltKey { get; init; } = string.Empty; } diff --git a/JwtStore.Infrastructure/Options/SecretsOptionsSetup.cs b/JwtStore.Infrastructure/Options/SecretsOptionsSetup.cs new file mode 100644 index 0000000..3a513f9 --- /dev/null +++ b/JwtStore.Infrastructure/Options/SecretsOptionsSetup.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; + +namespace JwtStore.Infrastructure.Options; + +public sealed class SecretsOptionsSetup(IConfiguration configuration) + : IConfigureOptions +{ + private readonly IConfiguration _configuration = configuration; + + public void Configure(SecretsOptions options) + => _configuration.GetSection(SecretsOptions.SectionName) + .Bind(options); +}