CodeLiturgy.Dashboard/CodeLiturgy.Views/StartupExtensions.cs

222 lines
8.0 KiB
C#
Raw Normal View History

2022-09-29 02:37:24 +03:00
using System.Text;
using BlueWest.Cryptography;
using BlueWest.Data.Application.Users;
using BlueWest.Data.Auth;
using BlueWest.Data.Auth.Context.Users;
2022-10-30 19:48:24 +03:00
using CodeLiturgy.Domain;
2022-09-29 02:37:24 +03:00
using BlueWest.WebApi.Context.Users;
2022-10-30 19:48:24 +03:00
using CodeLiturgy.Views.Utils;
2022-09-29 02:37:24 +03:00
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Redis.OM;
2022-10-30 19:48:24 +03:00
namespace CodeLiturgy.Views;
2022-09-29 02:37:24 +03:00
public static class StartupExtensions
{
2022-10-27 20:13:02 +03:00
private static MySqlServerVersion GetMySqlServerVersion(int major, int minor, int build) =>
new(new Version(major, minor, build));
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
private static string GetConnectionString(this IConfiguration configurationRoot, string db)
2022-09-29 02:37:24 +03:00
{
var startupMode = configurationRoot["mode"];
2022-10-27 20:13:02 +03:00
if (!string.IsNullOrEmpty(startupMode) && startupMode == "docker")
2022-09-29 02:37:24 +03:00
{
2022-10-27 20:13:02 +03:00
var config = configurationRoot.GetSection("ConnectionStringDocker")[db];
2022-09-29 02:37:24 +03:00
return config;
}
else
{
2022-10-27 20:13:02 +03:00
return configurationRoot.GetSection("ConnectionStringNoDocker")[db] ?? string.Empty;
2022-09-29 02:37:24 +03:00
}
2022-10-27 20:13:02 +03:00
}
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
private static bool IsDockerMode(this IConfiguration config)
{
var startupMode = config["mode"];
return startupMode == "docker";
2022-09-29 02:37:24 +03:00
}
2022-10-27 20:13:02 +03:00
internal static IServiceCollection AddAuthServerServices(this IServiceCollection services,
IConfiguration configuration, IWebHostEnvironment environment)
{
var connectionString = configuration.GetConnectionString("Redis");
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException("Redis connection string is empty");
}
services.AddSession(options =>
{
options.Cookie.Domain = SessionConstants.CookieDomain;
options.Cookie.HttpOnly = true;
options.IdleTimeout = TimeSpan.FromHours(8);
});
services
.AddSingleton(new RedisConnectionProvider(connectionString))
.AddScoped<IJwtTokenHandler, JwtTokenHandler>()
.AddScoped<IJwtFactory, JwtFactory>()
.AddHostedService<SessionManager>()
.AddSingleton<ISessionCache, SessionManager>()
.AddScoped<UserRepository>()
.AddScoped<IUserManager, ApplicationUserManager>()
.AddScoped<IAuthManager, AuthManager>()
.AddScoped<IHasher, Hasher>();
// Database Context and Swagger
// Register the ConfigurationBuilder instance of AuthSettings
var authSettings = configuration.GetSection(nameof(AuthSettings));
services.Configure<AuthSettings>(authSettings);
var signingKey = new SymmetricSecurityKey
(Encoding.ASCII.GetBytes(authSettings[nameof(AuthSettings.SecretKey)]));
// jwt wire up
// Get options from app settings
var jwtAppSettingOptions = configuration
.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials
(signingKey, SecurityAlgorithms.HmacSha256);
});
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
services.AddAuthentication(options =>
2022-09-29 02:37:24 +03:00
{
2022-10-27 20:13:02 +03:00
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(options =>
2022-09-29 02:37:24 +03:00
{
2022-10-27 20:13:02 +03:00
options.LoginPath = Routes.AuthLoginRoute;
options.LogoutPath = Routes.AuthLogoutRoute;
2022-09-29 02:37:24 +03:00
});
2022-10-27 20:13:02 +03:00
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy(SessionConstants.ApiNamePolicy,
2022-10-30 19:48:24 +03:00
policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol,
Constants.JwtClaims.ApiAccess));
2022-10-27 20:13:02 +03:00
});
// add identity
var identityBuilder = services.AddIdentityCore<ApplicationUser>(o =>
2022-09-29 02:37:24 +03:00
{
o.User.RequireUniqueEmail = true;
2022-10-27 20:13:02 +03:00
2022-09-29 02:37:24 +03:00
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
2022-10-27 20:13:02 +03:00
.AddUserManager<ApplicationUserManager>()
.AddUserStore<UserRepository>();
identityBuilder =
new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services);
identityBuilder
.AddEntityFrameworkStores<ApplicationUserDbContext>()
.AddDefaultTokenProviders();
return services;
}
/// <summary>
/// Get MYSQL Connection String
/// </summary>
/// <param name="optionsBuilder"></param>
/// <param name="configuration"></param>
/// <param name="environment"></param>
private static DbContextOptionsBuilder GetMySqlSettings(
this DbContextOptionsBuilder optionsBuilder,
IConfiguration configuration,
IWebHostEnvironment environment)
{
var sqlVersion = GetMySqlServerVersion(8, 0, 11);
// Docker / No-Docker
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
var mySqlConnectionString = configuration.GetConnectionString("MySQL");
if (mySqlConnectionString == string.Empty)
{
throw new InvalidOperationException("MySQL Connection string appears to be empty.");
2022-09-29 02:37:24 +03:00
}
2022-10-27 20:13:02 +03:00
optionsBuilder
.UseMySql(
mySqlConnectionString,
sqlVersion)
.UseMySql(sqlVersion,
builder => { builder.EnableRetryOnFailure(6, TimeSpan.FromSeconds(3), null); });
// The following three options help with debugging, but should
// be changed or removed for production.
if (environment.IsDevelopment())
{
optionsBuilder
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
return optionsBuilder;
}
2022-09-29 02:37:24 +03:00
2022-10-27 20:13:02 +03:00
/// <summary>
/// Setup database Contexts
/// </summary>
/// <param name="serviceCollection"></param>
/// <param name="configuration"></param>
/// <param name="environment"></param>
/// <returns></returns>
public static IServiceCollection PrepareMySqlDatabasePool(this IServiceCollection serviceCollection,
IConfiguration configuration, IWebHostEnvironment environment)
{
return serviceCollection
.AddDbContextPool<UserDbContext>(options =>
options.GetMySqlSettings(configuration, environment))
.AddDbContextPool<CountryDbContext>(options =>
options.GetMySqlSettings(configuration, environment))
.AddDbContextPool<ApplicationUserDbContext>(options =>
options.GetMySqlSettings(configuration, environment));
}
2022-09-29 02:37:24 +03:00
}