refactor: distribute configurations by classes

This commit is contained in:
2024-06-01 10:57:52 +03:00
parent ca02509b97
commit 78f589bb18
8 changed files with 275 additions and 173 deletions

View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.DependencyInjection;
namespace Mirea.Api.Endpoint.Configuration.AppConfig;
public static class ApiVersioningConfiguration
{
public static void AddCustomApiVersioning(this IServiceCollection services)
{
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = new UrlSegmentApiVersionReader();
});
services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
services.AddEndpointsApiExplorer();
}
}

View File

@ -0,0 +1,68 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Mirea.Api.Endpoint.Configuration.AppConfig;
public static class EnvironmentConfiguration
{
private static IDictionary<string, string> LoadEnvironment(string envFile)
{
Dictionary<string, string> environment = new();
if (!File.Exists(envFile)) return environment;
foreach (var line in File.ReadAllLines(envFile))
{
if (string.IsNullOrEmpty(line)) continue;
var commentIndex = line.IndexOf('#', StringComparison.Ordinal);
string arg = line;
if (commentIndex != -1)
arg = arg.Remove(commentIndex, arg.Length - commentIndex);
var parts = arg.Split(
'=',
StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 2)
parts = [parts[0], string.Join("=", parts[1..])];
if (parts.Length != 2)
continue;
environment.Add(parts[0].Trim(), parts[1].Trim());
}
return environment;
}
public static IConfigurationRoot GetEnvironment()
{
var variablesFromFile = LoadEnvironment(".env");
var environmentVariables = Environment.GetEnvironmentVariables()
.OfType<DictionaryEntry>()
.ToDictionary(
entry => entry.Key.ToString() ?? string.Empty,
entry => entry.Value?.ToString() ?? string.Empty
);
var result = new ConfigurationBuilder()
.AddInMemoryCollection(environmentVariables!)
.AddInMemoryCollection(variablesFromFile!);
#if DEBUG
result.AddInMemoryCollection(LoadEnvironment(".env.develop")!);
#endif
Environment.SetEnvironmentVariable("PATH_TO_SAVE", variablesFromFile["PATH_TO_SAVE"]);
return result.Build();
}
}

View File

@ -0,0 +1,66 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Mirea.Api.Endpoint.Common.Services.Security;
using Mirea.Api.Security.Common.Interfaces;
using System;
using System.Text;
namespace Mirea.Api.Endpoint.Configuration.AppConfig;
public static class JwtConfiguration
{
public static IServiceCollection AddJwtToken(this IServiceCollection services, IConfiguration configuration)
{
var lifeTimeJwt = TimeSpan.FromMinutes(int.Parse(configuration["SECURITY_LIFE_TIME_JWT"]!));
var jwtDecrypt = Encoding.UTF8.GetBytes(configuration["SECURITY_ENCRYPTION_TOKEN"] ?? string.Empty);
if (jwtDecrypt.Length != 32)
throw new InvalidOperationException("The secret token \"SECURITY_ENCRYPTION_TOKEN\" cannot be less than 32 characters long. Now the size is equal is " + jwtDecrypt.Length);
var jwtKey = Encoding.UTF8.GetBytes(configuration["SECURITY_SIGNING_TOKEN"] ?? string.Empty);
if (jwtKey.Length != 64)
throw new InvalidOperationException("The signature token \"SECURITY_SIGNING_TOKEN\" cannot be less than 64 characters. Now the size is " + jwtKey.Length);
var jwtIssuer = configuration["SECURITY_JWT_ISSUER"];
var jwtAudience = configuration["SECURITY_JWT_AUDIENCE"];
if (string.IsNullOrEmpty(jwtAudience) || string.IsNullOrEmpty(jwtIssuer))
throw new InvalidOperationException("The \"SECURITY_JWT_ISSUER\" and \"SECURITY_JWT_AUDIENCE\" are not specified");
services.AddSingleton<IAccessToken, JwtTokenService>(_ => new JwtTokenService
{
Audience = jwtAudience,
Issuer = jwtIssuer,
Lifetime = lifeTimeJwt,
EncryptionKey = jwtDecrypt,
SigningKey = jwtKey
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtIssuer,
ValidateAudience = true,
ValidAudience = jwtAudience,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(jwtKey),
TokenDecryptionKey = new SymmetricSecurityKey(jwtDecrypt)
};
});
return services;
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mirea.Api.Endpoint.Common.Services.Security;
using Mirea.Api.Endpoint.Configuration.General.Settings;
using Mirea.Api.Security;
using Mirea.Api.Security.Common.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.AppConfig;
public static class SecureConfiguration
{
public static IServiceCollection AddSecurity(this IServiceCollection services, IConfiguration configuration)
{
services.AddSecurityServices(configuration);
services.AddSingleton<IAccessToken, JwtTokenService>();
services.AddSingleton<IRevokedToken, MemoryRevokedTokenService>();
if (configuration.Get<CacheSettings>()?.TypeDatabase == CacheSettings.CacheEnum.Redis)
services.AddSingleton<ICacheService, DistributedCacheService>();
else
services.AddSingleton<ICacheService, MemoryCacheService>();
return services;
}
}

View File

@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Mirea.Api.Endpoint.Configuration.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.IO;
namespace Mirea.Api.Endpoint.Configuration.AppConfig;
public static class SwaggerConfiguration
{
public static IServiceCollection AddCustomSwagger(this IServiceCollection services)
{
services.AddSwaggerGen(options =>
{
options.SchemaFilter<SwaggerExampleFilter>();
options.OperationFilter<SwaggerDefaultValues>();
var basePath = AppDomain.CurrentDomain.BaseDirectory;
options.IncludeXmlComments(Path.Combine(basePath, "docs.xml"));
options.IncludeXmlComments(Path.Combine(basePath, "ApiDtoDocs.xml"));
});
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
return services;
}
public static IApplicationBuilder UseCustomSwagger(this IApplicationBuilder app, IServiceProvider services)
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
var provider = services.GetService<IApiVersionDescriptionProvider>();
foreach (var description in provider!.ApiVersionDescriptions)
{
var url = $"/swagger/{description.GroupName}/swagger.json";
var name = description.GroupName.ToUpperInvariant();
options.SwaggerEndpoint(url, name);
}
});
return app;
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.IO;
namespace Mirea.Api.Endpoint.Configuration;
internal static class EnvironmentManager
{
public static void LoadEnvironment(string envFile)
{
if (!File.Exists(envFile)) return;
foreach (var line in File.ReadAllLines(envFile))
{
if (string.IsNullOrEmpty(line)) continue;
var commentIndex = line.IndexOf('#', StringComparison.Ordinal);
string arg = line;
if (commentIndex != -1)
arg = arg.Remove(commentIndex, arg.Length - commentIndex);
var parts = arg.Split(
'=',
StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 2)
parts = [parts[0], string.Join("=", parts[1..])];
if (parts.Length != 2)
continue;
Environment.SetEnvironmentVariable(parts[0].Trim(), parts[1].Trim());
}
}
}

View File

@ -0,0 +1,16 @@
using Microsoft.OpenApi.Models;
using Mirea.Api.Endpoint.Common.Attributes;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
namespace Mirea.Api.Endpoint.Configuration.Swagger;
public class SwaggerExampleFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
var att = context.ParameterInfo?.GetCustomAttribute<SwaggerDefaultAttribute>();
if (att != null)
schema.Example = new Microsoft.OpenApi.Any.OpenApiString(att.Value);
}
}