refactor: move files to another namespace
This commit is contained in:
@ -0,0 +1,27 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Mirea.Api.Endpoint.Common.Settings;
|
||||
using Mirea.Api.Endpoint.Configuration.General.Settings;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
|
||||
|
||||
public static class CacheConfiguration
|
||||
{
|
||||
public static IServiceCollection AddCustomRedis(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var cache = configuration.Get<GeneralConfig>()?.CacheSettings;
|
||||
if (cache?.TypeDatabase == CacheSettings.CacheEnum.Redis)
|
||||
{
|
||||
services.AddStackExchangeRedisCache(options =>
|
||||
{
|
||||
options.Configuration = cache.ConnectionString;
|
||||
options.InstanceName = "mirea_";
|
||||
});
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
|
||||
|
||||
public static class EnvironmentConfiguration
|
||||
{
|
||||
private static Dictionary<string, string> LoadEnvironment(string envFile)
|
||||
{
|
||||
Dictionary<string, string> environment = [];
|
||||
|
||||
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");
|
||||
|
||||
#if DEBUG
|
||||
LoadEnvironment(".env.develop").ToList().ForEach(x => variablesFromFile.Add(x.Key, x.Value));
|
||||
#endif
|
||||
|
||||
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 (variablesFromFile.TryGetValue("PATH_TO_SAVE", out var pathToSave))
|
||||
{
|
||||
Environment.SetEnvironmentVariable("PATH_TO_SAVE", pathToSave);
|
||||
if (!Directory.Exists(pathToSave))
|
||||
Directory.CreateDirectory(pathToSave);
|
||||
}
|
||||
|
||||
if (variablesFromFile.TryGetValue("ACTUAL_SUB_PATH", out var actualSubPath))
|
||||
Environment.SetEnvironmentVariable("ACTUAL_SUB_PATH", actualSubPath);
|
||||
|
||||
if (variablesFromFile.TryGetValue("SWAGGER_SUB_PATH", out var swaggerSubPath))
|
||||
Environment.SetEnvironmentVariable("SWAGGER_SUB_PATH", swaggerSubPath);
|
||||
|
||||
return result.Build();
|
||||
}
|
||||
}
|
@ -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.ApplicationConfiguration;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Endpoint.Common.Settings;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Serilog.Filters;
|
||||
using Serilog.Formatting.Compact;
|
||||
using System.IO;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
|
||||
|
||||
public static class LoggerConfiguration
|
||||
{
|
||||
public static IHostBuilder AddCustomSerilog(this IHostBuilder hostBuilder)
|
||||
{
|
||||
hostBuilder.UseSerilog((context, _, configuration) =>
|
||||
{
|
||||
var generalConfig = context.Configuration.Get<GeneralConfig>()?.LogSettings;
|
||||
configuration
|
||||
.MinimumLevel.Debug()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console(
|
||||
outputTemplate:
|
||||
"[{Level:u3}] [{Timestamp:dd.MM.yyyy HH:mm:ss}] {Message:lj}{NewLine}{Exception}");
|
||||
|
||||
if (generalConfig?.EnableLogToFile == true)
|
||||
{
|
||||
generalConfig.LogFilePath = PathBuilder.Combine(generalConfig.LogFilePath ?? string.Empty);
|
||||
|
||||
if (!string.IsNullOrEmpty(generalConfig.LogFilePath) && Directory.Exists(generalConfig.LogFilePath))
|
||||
Directory.CreateDirectory(generalConfig.LogFilePath);
|
||||
|
||||
configuration.WriteTo.File(
|
||||
new CompactJsonFormatter(),
|
||||
PathBuilder.Combine(
|
||||
generalConfig.LogFilePath!,
|
||||
generalConfig.LogFileName + ".json"
|
||||
),
|
||||
LogEventLevel.Debug,
|
||||
rollingInterval: RollingInterval.Day);
|
||||
}
|
||||
|
||||
configuration
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning);
|
||||
|
||||
configuration.Filter.ByExcluding(Matching.WithProperty<string>("SourceContext", sc =>
|
||||
sc.Contains("Microsoft.EntityFrameworkCore.Database.Command")));
|
||||
});
|
||||
|
||||
return hostBuilder;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseCustomSerilog(this IApplicationBuilder app)
|
||||
{
|
||||
app.UseSerilogRequestLogging(options =>
|
||||
{
|
||||
options.MessageTemplate = "[{RequestMethod}] {RequestPath} [Client {RemoteIPAddress}] [{StatusCode}] in {Elapsed:0.0000} ms";
|
||||
|
||||
options.GetLevel = (_, elapsed, ex) => elapsed >= 2500 || ex != null
|
||||
? LogEventLevel.Warning
|
||||
: elapsed >= 1000
|
||||
? LogEventLevel.Information
|
||||
: LogEventLevel.Debug;
|
||||
|
||||
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
|
||||
{
|
||||
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
|
||||
diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
|
||||
diagnosticContext.Set("UserAgent", httpContext.Request.Headers.UserAgent);
|
||||
diagnosticContext.Set("RemoteIPAddress", httpContext.Connection.RemoteIpAddress?.ToString());
|
||||
};
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Mirea.Api.Endpoint.Common.Services.Security;
|
||||
using Mirea.Api.Endpoint.Common.Settings;
|
||||
using Mirea.Api.Endpoint.Configuration.General.Settings;
|
||||
using Mirea.Api.Security;
|
||||
using Mirea.Api.Security.Common.Interfaces;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
|
||||
|
||||
public static class SecureConfiguration
|
||||
{
|
||||
public static IServiceCollection AddSecurity(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddSecurityServices(configuration);
|
||||
|
||||
services.AddSingleton<IRevokedToken, MemoryRevokedTokenService>();
|
||||
|
||||
if (configuration.Get<GeneralConfig>()?.CacheSettings?.TypeDatabase == CacheSettings.CacheEnum.Redis)
|
||||
services.AddSingleton<ICacheService, DistributedCacheService>();
|
||||
else
|
||||
services.AddSingleton<ICacheService, MemoryCacheService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Endpoint.Configuration.SwaggerOptions;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.ApplicationConfiguration;
|
||||
|
||||
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.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Keep the JWT token in the field (Bearer token)",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
});
|
||||
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
[]
|
||||
}
|
||||
});
|
||||
|
||||
if (File.Exists(Path.Combine(basePath, "docs.xml")))
|
||||
options.IncludeXmlComments(Path.Combine(basePath, "docs.xml"));
|
||||
|
||||
if (File.Exists(Path.Combine(basePath, "ApiDtoDocs.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 =>
|
||||
{
|
||||
options.InjectStylesheet($"{UrlHelper.GetSubPath}css/swagger/SwaggerDark.css");
|
||||
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);
|
||||
options.RoutePrefix = UrlHelper.GetSubPathSwagger.Trim('/');
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user