This commit is contained in:
CodeLiturgy 2022-09-10 05:12:03 +01:00
parent 2a404c3560
commit 5c32055f6a
28 changed files with 267 additions and 232 deletions

View File

@ -1,4 +1,5 @@
using BlueWest.Data; using BlueWest.Data;
using BlueWest.WebApi.Context.Users;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace BlueWest.WebApi.EF.Model namespace BlueWest.WebApi.EF.Model
@ -24,6 +25,7 @@ namespace BlueWest.WebApi.EF.Model
.ConfigureDatabaseKeys() .ConfigureDatabaseKeys()
.CurrencyModel() .CurrencyModel()
.ConfigureUserModel(); .ConfigureUserModel();
//.ConfigureIdentityModel();
} }
#endregion #endregion
@ -123,6 +125,40 @@ namespace BlueWest.WebApi.EF.Model
#endregion #endregion
public static void ConfigureIdentityModel(this ModelBuilder builder)
{
builder.Entity<ApplicationUser>(b =>
{
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
});
builder.Entity<ApplicationRole>(b =>
{
b.HasKey(r => r.Id);
b.HasIndex(r => r.NormalizedName).HasDatabaseName("RoleNameIndex").IsUnique();
b.ToTable("Roles");
b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();
b.Property(u => u.Name).HasMaxLength(256);
b.Property(u => u.NormalizedName).HasMaxLength(256);
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
b.HasMany<ApplicationRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
});
builder.Entity<ApplicationRoleClaim>(b =>
{
b.HasKey(rc => rc.Id);
b.ToTable("RoleClaims");
});
builder.Entity<ApplicationUserRole>(b =>
{
b.HasKey(r => new { r.UserId, r.RoleId });
b.ToTable("UserRoles");
});
}
} }
} }

View File

@ -8,25 +8,18 @@
/// <param name="where">Optional where predicate.</param> /// <param name="where">Optional where predicate.</param>
/// <param name="orderBy">Optional order by predicate.</param> /// <param name="orderBy">Optional order by predicate.</param>
/// <returns>A bool if the result is successful and a projection of the first occurrence of {propertyName}. </returns> /// <returns>A bool if the result is successful and a projection of the first occurrence of {propertyName}. </returns>
public static (bool, {returnTypeFullName}[]) Get{propertyName}(this {contextFullName} dbContext, int skip = 0, int take = 50, int orderDir = 1, public static (bool, System.Collections.Generic.List<{returnTypeFullName}>) Get{propertyName}(this {contextFullName} dbContext, int skip = 0, int take = 50, int orderDir = 1)
Expression <Func<{returnTypeFullName}, bool> > where = null,
Expression <Func<{returnTypeFullName}, object> > orderBy = null)
{ {
if (take > 200) take = 200; if (take > 200) take = 200;
var query = dbContext var query = dbContext
.{propertyName} .{propertyName}
.Select(x => new {returnTypeFullName}(x))
.Skip(skip) .Skip(skip)
.Take(take); .Take(take)
.Select(x => new {returnTypeFullName}(x));
if (where != null) query = query.Where(where);
if(orderBy != null) var result = query.ToList();
{
if (orderDir == 1) query = query.OrderBy(orderBy);
else query = query.OrderByDescending(orderBy);
}
return (query.Any(), query.ToArray()); return (result.Any(), result);
} }

View File

@ -1,6 +1,5 @@
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper;
using BlueWest.WebApi.Context.Users; using BlueWest.WebApi.Context.Users;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
@ -11,24 +10,36 @@ using Microsoft.AspNetCore.Mvc;
namespace BlueWest.WebApi.Controllers; namespace BlueWest.WebApi.Controllers;
/// <summary>
/// Auth controller
/// </summary>
[Route("api/[controller]")] [Route("api/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)] [Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
[ApiController] [ApiController]
public class AuthController : Controller public class AuthController : Controller
{ {
private readonly IMapper _mapper;
private readonly IAuthManager _authManager; private readonly IAuthManager _authManager;
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
public AuthController( IMapper mapper, IAuthManager authManager, IUserManager userManager) /// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="authManager"></param>
/// <param name="userManager"></param>
public AuthController( IAuthManager authManager, IUserManager userManager)
{ {
_mapper = mapper;
_authManager = authManager; _authManager = authManager;
_userManager = userManager; _userManager = userManager;
} }
/// <summary>
/// Signup user
/// </summary>
/// <param name="registerViewModel"></param>
/// <returns></returns>
[AllowAnonymous] [AllowAnonymous]
[HttpPost("register")] [HttpPost("register")]
public async Task<ActionResult<IdentityResult>> SignupUserAsync(RegisterViewModel registerViewModel) public async Task<ActionResult<IdentityResult>> SignupUserAsync(RegisterViewModel registerViewModel)
@ -45,7 +56,7 @@ namespace BlueWest.WebApi.Controllers;
if (loginResultSucceded != null) if (loginResultSucceded != null)
{ {
return Ok(_mapper.Map<AccessToken>(loginResultSucceded)); return Ok(loginResultSucceded);
} }
return Problem(); return Problem();
@ -58,7 +69,6 @@ namespace BlueWest.WebApi.Controllers;
{ {
var user = await _userManager.FindByEmailAsync(loginDto.Email); var user = await _userManager.FindByEmailAsync(loginDto.Email);
if (user != null) if (user != null)
{ {
if(await _userManager.CheckPasswordAsync(user, loginDto.Password)) if(await _userManager.CheckPasswordAsync(user, loginDto.Password))
@ -78,8 +88,6 @@ namespace BlueWest.WebApi.Controllers;
public async Task<ActionResult<IdentityResult>> DoLogoutAsync(LoginViewModel loginDto) public async Task<ActionResult<IdentityResult>> DoLogoutAsync(LoginViewModel loginDto)
{ {
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Json(true); return Json(true);
} }

View File

@ -4,6 +4,9 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using BlueWest.Data; using BlueWest.Data;
using BlueWest.WebApi.EF; using BlueWest.WebApi.EF;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -14,6 +17,8 @@ namespace BlueWest.WebApi.Controllers
/// </summary> /// </summary>
[ApiController] [ApiController]
[Route("[controller]")] [Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public class CountryController : ControllerBase public class CountryController : ControllerBase
{ {

View File

@ -3,6 +3,9 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using BlueWest.Data; using BlueWest.Data;
using BlueWest.WebApi.EF; using BlueWest.WebApi.EF;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -13,6 +16,8 @@ namespace BlueWest.WebApi.Controllers
/// </summary> /// </summary>
[ApiController] [ApiController]
[Route("[controller]")] [Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public partial class CurrencyController : ControllerBase public partial class CurrencyController : ControllerBase
{ {
@ -40,7 +45,7 @@ namespace BlueWest.WebApi.Controllers
[HttpGet] [HttpGet]
public ActionResult GetCurrencies(int skip = 0, int take = 50, int orderDir = 1) public ActionResult GetCurrencies(int skip = 0, int take = 50, int orderDir = 1)
{ {
var (success, result) = _dbContext.GetCurrencies(skip, take, orderDir, null, x => x.Id); var (success, result) = _dbContext.GetCurrencies(skip, take, orderDir);
if (success) if (success)
{ {

View File

@ -1,6 +1,9 @@
using System; using System;
using BlueWest.Data; using BlueWest.Data;
using BlueWest.WebApi.EF; using BlueWest.WebApi.EF;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -11,6 +14,8 @@ namespace BlueWest.WebApi.Controllers;
/// </summary> /// </summary>
[ApiController] [ApiController]
[Route("[controller]")] [Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public class FinanceController : ControllerBase public class FinanceController : ControllerBase
{ {
private readonly FinanceDbContext _dbContext; private readonly FinanceDbContext _dbContext;

View File

@ -4,6 +4,9 @@ using System.Collections.Immutable;
using System.Linq; using System.Linq;
using BlueWest.Data; using BlueWest.Data;
using BlueWest.WebApi.EF; using BlueWest.WebApi.EF;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -14,6 +17,8 @@ namespace BlueWest.WebApi.Controllers
/// </summary> /// </summary>
[ApiController] [ApiController]
[Route("[controller]")] [Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public class UserController : ControllerBase public class UserController : ControllerBase
{ {

View File

@ -71,40 +71,42 @@ namespace BlueWest.WebApi
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath); options.IncludeXmlComments(xmlPath);
});
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
services.Configure<IdentityOptions>(options =>
{ {
// Password settings. Description =
options.Password.RequireDigit = true; "JWT Authorization header using the Bearer scheme (Example: 'Bearer 12345abcdef')",
options.Password.RequireLowercase = true; Name = "Authorization",
options.Password.RequireNonAlphanumeric = true; In = ParameterLocation.Header,
options.Password.RequireUppercase = true; Type = SecuritySchemeType.ApiKey,
options.Password.RequiredLength = 6; Scheme = "Bearer"
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
options.User.RequireUniqueEmail = false;
}); });
services.AddScoped<SignInManager>(); options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
services.AddScoped<RoleManager>(); {
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
/*
services.AddSingleton<IFileProvider>( services.AddSingleton<IFileProvider>(
new PhysicalFileProvider( new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/ImageFiles") Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/ImageFiles")
) )
); );
*/
IConfigurationRoot configuration = new ConfigurationBuilder() IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("config.json") .AddJsonFile("config.json")
@ -115,6 +117,7 @@ namespace BlueWest.WebApi
services services
.AddSingleton<EventManager>(); .AddSingleton<EventManager>();
switch (allowedDatabase) switch (allowedDatabase)
{ {
case "mysql": case "mysql":
@ -129,6 +132,9 @@ namespace BlueWest.WebApi
throw new InvalidOperationException("config.json doesn't specify a valid database. Use mysql or sqlite."); throw new InvalidOperationException("config.json doesn't specify a valid database. Use mysql or sqlite.");
} }
services.AddAuthServerServices(MyAllowSpecificOrigins, _configuration, _environment);
services.AddScoped<ExchangeInterface>(); services.AddScoped<ExchangeInterface>();
@ -154,9 +160,11 @@ namespace BlueWest.WebApi
c.RoutePrefix = "swagger"; c.RoutePrefix = "swagger";
c.SwaggerEndpoint("/swagger/v1/swagger.json", "BlueWest.Api v1"); c.SwaggerEndpoint("/swagger/v1/swagger.json", "BlueWest.Api v1");
}); });
app.UseStaticFiles(); //app.UseStaticFiles();
//app.UseHttpsRedirection(); //app.UseHttpsRedirection();
app.UseRouting(); app.UseRouting();
app.UseCors(MyAllowSpecificOrigins); app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication(); app.UseAuthentication();

View File

@ -79,7 +79,8 @@ namespace BlueWest.WebApi
.AddDbContextPool<UserDbContext>(options => options.GetMySqlSettings(configuration, environment)) .AddDbContextPool<UserDbContext>(options => options.GetMySqlSettings(configuration, environment))
.AddDbContextPool<CountryDbContext>(options => options.GetMySqlSettings(configuration, environment)) .AddDbContextPool<CountryDbContext>(options => options.GetMySqlSettings(configuration, environment))
.AddDbContextPool<FinanceDbContext>(options => options.GetMySqlSettings(configuration, environment)) .AddDbContextPool<FinanceDbContext>(options => options.GetMySqlSettings(configuration, environment))
.AddDbContextPool<CompanyDbContext>(options => options.GetMySqlSettings(configuration, environment)); .AddDbContextPool<CompanyDbContext>(options => options.GetMySqlSettings(configuration, environment))
.AddDbContextPool<ApplicationUserDbContext>(options => options.GetMySqlSettings(configuration, environment));
} }
/// <summary> /// <summary>
@ -99,39 +100,41 @@ namespace BlueWest.WebApi
.AddDbContextPool<CountryDbContext>(options => options.UseSqlite(sqliteConString)) .AddDbContextPool<CountryDbContext>(options => options.UseSqlite(sqliteConString))
.AddDbContextPool<FinanceDbContext>(options => options.UseSqlite(sqliteConString)) .AddDbContextPool<FinanceDbContext>(options => options.UseSqlite(sqliteConString))
.AddDbContextPool<CompanyDbContext>(options => options.UseSqlite(sqliteConString)); .AddDbContextPool<CompanyDbContext>(options => options.UseSqlite(sqliteConString));
} }
public static void AddAuthServerServices(this IServiceCollection services, string origins, IConfiguration _configuration) public static IServiceCollection AddAuthServerServices(this IServiceCollection services, string origins, IConfiguration configuration , IWebHostEnvironment environment)
{ {
var sqliteConString = "Data Source=BlueWest.Api.db";
services.AddDbContext<ApplicationUserDbContext>(options => options.UseSqlite(sqliteConString));
services.AddScoped<IJwtTokenHandler, JwtTokenHandler>(); services.AddScoped<IJwtTokenHandler, JwtTokenHandler>();
services.AddScoped<IJwtFactory, JwtFactory>(); services.AddScoped<IJwtFactory, JwtFactory>();
// User management
services
.AddScoped<UserRepository>()
.AddScoped<IUserManager, UserManager>()
.AddScoped<IAuthManager, AuthManager>()
.AddScoped<IHasher, Hasher>();
services services
.AddIdentityCore<ApplicationUser>(opt => { opt.User.RequireUniqueEmail = true; }) .AddIdentityCore<ApplicationUser>(opt => { opt.User.RequireUniqueEmail = true; })
.AddEntityFrameworkStores<UserDbContext>()
.AddUserManager<UserManager>() .AddUserManager<UserManager>()
.AddUserStore<UserRepository>(); .AddUserStore<UserRepository>();
// Database Context and Swagger // Database Context and Swagger
services.TryAddSingleton<ISystemClock, SystemClock>();
// Registering 'services' and Authentication, Cookies, JWT
services
.AddScoped<IUsersRepo, UserRepository>()
.AddScoped<IUserManager, UserManager>() // So it gets successfully registered in UserManager
.AddScoped<IAuthManager, AuthManager>()
.AddScoped<IHasher, Hasher>();
// Register the ConfigurationBuilder instance of AuthSettings // Register the ConfigurationBuilder instance of AuthSettings
var authSettings = _configuration.GetSection(nameof(AuthSettings)); var authSettings = configuration.GetSection(nameof(AuthSettings));
services.Configure<AuthSettings>(authSettings); services.Configure<AuthSettings>(authSettings);
var signingKey = new SymmetricSecurityKey var signingKey = new SymmetricSecurityKey
(Encoding.ASCII.GetBytes(authSettings[nameof(AuthSettings.SecretKey)])); (Encoding.ASCII.GetBytes(authSettings[nameof(AuthSettings.SecretKey)]));
// jwt wire up // jwt wire up
// Get options from app settings // Get options from app settings
var jwtAppSettingOptions = _configuration var jwtAppSettingOptions = configuration
.GetSection(nameof(JwtIssuerOptions)); .GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions // Configure JwtIssuerOptions
@ -169,7 +172,7 @@ namespace BlueWest.WebApi
}) })
.AddCookie(options => .AddCookie(options =>
{ {
options.LoginPath = "/api/auth/login2"; options.LoginPath = "/api/auth/login";
options.LogoutPath = "/api/auth/logout"; options.LogoutPath = "/api/auth/logout";
}) })
.AddJwtBearer(configureOptions => .AddJwtBearer(configureOptions =>
@ -202,7 +205,7 @@ namespace BlueWest.WebApi
}); });
// add identity // add identity
var identityBuilder = services.AddIdentityCore<User>(o => var identityBuilder = services.AddIdentityCore<ApplicationUser>(o =>
{ {
// configure identity options // configure identity options
o.Password.RequireDigit = false; o.Password.RequireDigit = false;
@ -212,28 +215,14 @@ namespace BlueWest.WebApi
o.Password.RequiredLength = 6; o.Password.RequiredLength = 6;
}); });
identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(IdentityRole), identityBuilder.Services); identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services);
identityBuilder.AddEntityFrameworkStores<UserDbContext>().AddDefaultTokenProviders(); identityBuilder
} .AddEntityFrameworkStores<ApplicationUserDbContext>()
public static void ConfigureApiWithUsers(this IApplicationBuilder app, IWebHostEnvironment env, string origins) .AddDefaultTokenProviders();
{
if (env.IsDevelopment()) return services;
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
} }
app.UseSwagger()
.UseSwaggerUI(config => { config.SwaggerEndpoint("/swagger/v1/swagger.json", "Commands And Snippets API"); })
.UseRouting()
.UseAuthentication()
.UseAuthorization()
.UseCors(origins)
.UseEndpoints(endpoints => endpoints.MapControllers());
}
} }
} }

View File

@ -0,0 +1,6 @@
dotnet ef database update -c ApplicationUserDbContext
dotnet ef database update -c CountryDbContext
dotnet ef database update -c CompanyDbContext
dotnet ef database update -c UserDbContext

View File

@ -1,4 +1,6 @@
using System; using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
namespace BlueWest.WebApi.Context.Users; namespace BlueWest.WebApi.Context.Users;
@ -12,8 +14,9 @@ public class ApplicationUser : IdentityUser<string>
/// <summary> /// <summary>
/// Gets or sets the primary key for this user. /// Gets or sets the primary key for this user.
/// </summary> /// </summary>
[PersonalData] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public new Guid Id { get; set; } [PersonalData]
public new string Id { get; set; }
/// <summary> /// <summary>
/// Gets or sets the user name for this user. /// Gets or sets the user name for this user.

View File

@ -22,22 +22,8 @@ public class ApplicationUserDbContext : IdentityDbContext<
ApplicationUserRole, ApplicationUserRole,
ApplicationUserLogin, ApplicationUserLogin,
ApplicationRoleClaim, ApplicationRoleClaim,
ApplicationUserToken>, IPersistedGrantDbContext ApplicationUserToken>
{ {
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
/// </summary>
public override DbSet<ApplicationUserRole> UserRoles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
/// </summary>
public override DbSet<ApplicationRole> Roles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
/// </summary>
public override DbSet<ApplicationRoleClaim> RoleClaims { get; set; }
/// <summary> /// <summary>
/// Configures the schema needed for the identity framework. /// Configures the schema needed for the identity framework.
@ -50,9 +36,10 @@ public class ApplicationUserDbContext : IdentityDbContext<
/// Database for the context of database users /// Database for the context of database users
/// </summary> /// </summary>
/// <param name="options"></param> /// <param name="options"></param>
public ApplicationUserDbContext(DbContextOptions<UserDbContext> options) : base(options) public ApplicationUserDbContext(DbContextOptions<ApplicationUserDbContext> options) : base(options)
{ {
Database.EnsureCreated(); Database.EnsureCreated();
} }
/// <summary> /// <summary>
@ -64,13 +51,19 @@ public class ApplicationUserDbContext : IdentityDbContext<
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)
{ {
base.OnModelCreating(builder); base.OnModelCreating(builder);
builder.ConfigureCurrentDbModel();
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(b => builder.Entity<ApplicationUser>(b =>
{ {
b.HasMany<ApplicationUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired(); b.HasMany<ApplicationUserRole>()
.WithOne()
.HasForeignKey(ur => ur.UserId).IsRequired();
}); });
builder.Entity<ApplicationUser>().ToTable("ApplicationUser")
.HasKey(x => x.Id);
builder.Entity<ApplicationRole>(b => builder.Entity<ApplicationRole>(b =>
{ {
b.HasKey(r => r.Id); b.HasKey(r => r.Id);
@ -96,14 +89,8 @@ public class ApplicationUserDbContext : IdentityDbContext<
b.HasKey(r => new { r.UserId, r.RoleId }); b.HasKey(r => new { r.UserId, r.RoleId });
b.ToTable("UserRoles"); b.ToTable("UserRoles");
}); });
builder.ConfigureCurrentDbModel();
} }
public Task<int> SaveChangesAsync()
{
return SaveChangesAsync();
}
public DbSet<PersistedGrant> PersistedGrants { get; set; }
public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
public DbSet<Key> Keys { get; set; }
} }

View File

@ -1,6 +1,5 @@
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper;
using BlueWest.Cryptography; using BlueWest.Cryptography;
using BlueWest.Data; using BlueWest.Data;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
@ -10,21 +9,26 @@ namespace BlueWest.WebApi.Context.Users;
public class AuthManager : IAuthManager public class AuthManager : IAuthManager
{ {
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly IUsersRepo _usersRepo; private readonly UserRepository _usersRepo;
private readonly IHasher _hasher; private readonly IHasher _hasher;
private readonly IMapper _mapper;
private readonly IJwtFactory _jwtFactory; private readonly IJwtFactory _jwtFactory;
public AuthManager(IUserManager userManager, IHasher hasher, IMapper mapper /// <summary>
, IUsersRepo usersRepo, IJwtFactory jwtFactory) /// Auth manager constructor
/// </summary>
/// <param name="userManager"></param>
/// <param name="hasher"></param>
/// <param name="usersRepo"></param>
/// <param name="jwtFactory"></param>
public AuthManager(IUserManager userManager, IHasher hasher, UserRepository usersRepo, IJwtFactory jwtFactory)
{ {
_userManager = userManager; _userManager = userManager;
_hasher = hasher; _hasher = hasher;
_mapper = mapper;
_usersRepo = usersRepo; _usersRepo = usersRepo;
_jwtFactory = jwtFactory; _jwtFactory = jwtFactory;
} }
/// <inheritdoc />
public async Task<AccessToken> GetToken(LoginViewModel loginViewModel) public async Task<AccessToken> GetToken(LoginViewModel loginViewModel)
{ {
if (!string.IsNullOrEmpty(loginViewModel.Email) && !string.IsNullOrEmpty(loginViewModel.Password)) if (!string.IsNullOrEmpty(loginViewModel.Email) && !string.IsNullOrEmpty(loginViewModel.Password))
@ -48,6 +52,7 @@ public class AuthManager : IAuthManager
return null; return null;
} }
/// <inheritdoc />
public async Task<bool> VerifyLoginAsync(string email, string password) public async Task<bool> VerifyLoginAsync(string email, string password)
{ {
var user = await _userManager.FindByEmailAsync(email); var user = await _userManager.FindByEmailAsync(email);
@ -74,7 +79,8 @@ public class AuthManager : IAuthManager
public async Task<IdentityResult> CreateUserAsync(RegisterViewModel userSignupDto) public async Task<IdentityResult> CreateUserAsync(RegisterViewModel userSignupDto)
{ {
RegisterViewModel userToCreate = FromSignupToUser(userSignupDto);
return await _userManager.CreateAsync(userSignupDto.ToUser()); return await _userManager.CreateAsync(userToCreate.ToUser());
} }
} }

View File

@ -4,12 +4,31 @@ using Microsoft.AspNetCore.Identity;
namespace BlueWest.WebApi.Context.Users; namespace BlueWest.WebApi.Context.Users;
/// <summary>
/// Auth manager contract interface.
/// </summary>
public interface IAuthManager public interface IAuthManager
{ {
/// <summary>
/// CreateUserAsync
/// </summary>
/// <param name="registerViewModel"></param>
/// <returns></returns>
Task<IdentityResult> CreateUserAsync(RegisterViewModel registerViewModel); Task<IdentityResult> CreateUserAsync(RegisterViewModel registerViewModel);
/// <summary>
/// VerifyLoginAsync
/// </summary>
/// <param name="email"></param>
/// <param name="password"></param>
/// <returns></returns>
Task<bool> VerifyLoginAsync(string email, string password); Task<bool> VerifyLoginAsync(string email, string password);
/// <summary>
/// GetToken
/// </summary>
/// <param name="loginViewModel"></param>
/// <returns></returns>
Task<AccessToken> GetToken(LoginViewModel loginViewModel); Task<AccessToken> GetToken(LoginViewModel loginViewModel);
} }

View File

@ -1,23 +0,0 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BlueWest.Data;
using Microsoft.AspNetCore.Identity;
namespace BlueWest.WebApi.Context.Users;
/// <summary>
/// This is our Users repository.
/// Since this is a simple app we'll have the following roles
/// Admin and APIClient
/// </summary>
public interface IUsersRepo : IUserStore<ApplicationUser>
{
public Task<IEnumerable<ApplicationUser>> GetUsers();
public Task CreateUser(ApplicationUser user);
public Task SaveChanges();
public Task<ApplicationUser> GetUserById(string id);
Task<ApplicationUser> FindByEmailAsync(string email, CancellationToken cancellationToken);
}

View File

@ -23,6 +23,7 @@ public class RegisterViewModel
[DataType(DataType.Password)] [DataType(DataType.Password)]
[Display(Name = "Password")] [Display(Name = "Password")]
public string Password { get; set; } public string Password { get; set; }
public string Username { get; set; }
/// <summary> /// <summary>
/// ConfirmPassword /// ConfirmPassword
@ -37,6 +38,7 @@ public class RegisterViewModel
var newUser = new ApplicationUser(); var newUser = new ApplicationUser();
newUser.Email = Email; newUser.Email = Email;
newUser.PasswordHash = Password; newUser.PasswordHash = Password;
newUser.UserName = Username;
return newUser; return newUser;
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BlueWest.Cryptography; using BlueWest.Cryptography;
using BlueWest.Data; using BlueWest.Data;
@ -12,8 +13,8 @@ namespace BlueWest.WebApi.Context.Users;
public class UserManager : UserManager<ApplicationUser>, IUserManager public class UserManager : UserManager<ApplicationUser>, IUserManager
{ {
private readonly IHasher _hasher; private readonly IHasher _hasher;
private readonly IUsersRepo _usersRepo; private readonly UserRepository _usersRepo;
public UserManager(IUsersRepo store, IOptions<IdentityOptions> optionsAccessor, public UserManager(UserRepository store, IOptions<IdentityOptions> optionsAccessor,
IHasher passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators, IHasher passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer, IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger) : base(store, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger) : base(store,
@ -24,24 +25,6 @@ public class UserManager : UserManager<ApplicationUser>, IUserManager
_usersRepo = store; _usersRepo = store;
} }
public override async Task<IdentityResult> CreateAsync(ApplicationUser user)
{
ThrowIfDisposed();
var result = await ValidateUserAsync(user);
if (!result.Succeeded)
{
return result;
}
if (Options.Lockout.AllowedForNewUsers && SupportsUserLockout)
{
// await GetUserLockoutStore().SetLockoutEnabledAsync(user, true, CancellationToken);
}
await UpdateNormalizedUserNameAsync(user);
await UpdateNormalizedEmailAsync(user);
return await _usersRepo.CreateAsync(user, CancellationToken);
}
public override async Task<bool> CheckPasswordAsync(ApplicationUser user, string password) public override async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@ -80,27 +63,6 @@ public class UserManager : UserManager<ApplicationUser>, IUserManager
return PasswordHasher.VerifyHashedPassword(user, existingHash, password); return PasswordHasher.VerifyHashedPassword(user, existingHash, password);
} }
public override async Task<ApplicationUser> FindByNameAsync(string userName)
{
if (userName == null)
{
throw new ArgumentNullException(nameof(userName));
}
ApplicationUser user;
if (Store is IUsersRepo repo)
{
user = await repo.FindByNameAsync(userName, CancellationToken);
}
else
{
userName = NormalizeName(userName);
user = await Store.FindByNameAsync(userName, CancellationToken);
}
return user;
}
public override async Task<IdentityResult> ChangePasswordAsync(ApplicationUser user, string currentPassword, string newPassword) public override async Task<IdentityResult> ChangePasswordAsync(ApplicationUser user, string currentPassword, string newPassword)
@ -137,19 +99,4 @@ public class UserManager : UserManager<ApplicationUser>, IUserManager
return null; return null;
} }
public override async Task<ApplicationUser> FindByEmailAsync(string email)
{
ApplicationUser user = null;
if (Store is IUsersRepo repo)
{
user = await repo.FindByEmailAsync(email, CancellationToken);
}
else
{
user = await Store.FindByNameAsync(email, CancellationToken);
}
return user;
}
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -12,7 +13,7 @@ namespace BlueWest.WebApi.Context.Users;
/// <summary> /// <summary>
/// Users Repository /// Users Repository
/// </summary> /// </summary>
public class UserRepository : UserStore<ApplicationUser, ApplicationRole, ApplicationUserDbContext>, IUsersRepo public class UserRepository : UserStore<ApplicationUser, ApplicationRole, ApplicationUserDbContext>
{ {
private readonly ApplicationUserDbContext _context; private readonly ApplicationUserDbContext _context;
@ -35,34 +36,48 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
/// Create Application User /// Create Application User
/// </summary> /// </summary>
/// <param name="user"></param> /// <param name="user"></param>
public async Task CreateUser(ApplicationUser user) /*public override async Task<IdentityResult> CreateAsync(ApplicationUser user, CancellationToken cancellationToken = default(CancellationToken))
{ {
await CreateAsync(user, CancellationToken.None); cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
} }
await _context.AddAsync(user, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
return IdentityResult.Success;
}*/
/// <summary> /// <summary>
/// Save Changes /// Save Changes
/// </summary> /// </summary>
/*
public async Task SaveChanges() public async Task SaveChanges()
{ {
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
*/
/*
private async Task<bool> SaveChanges(ApplicationUser user) private async Task<bool> SaveChanges(ApplicationUser user)
{ {
_context.Users.Update(user); _context.Users.Update(user);
return await _context.SaveChangesAsync() > 0; return await _context.SaveChangesAsync() > 0;
} }
*/
/// <summary> /// <summary>
/// Dispose repository /// Dispose repository
/// </summary> /// </summary>
/*
public void Dispose() public void Dispose()
{ {
_context.Dispose(); _context.Dispose();
} }
*/
/*
/// <inheritdoc /> /// <inheritdoc />
public override Task<string> GetUserIdAsync(ApplicationUser user, CancellationToken cancellationToken = default) public override Task<string> GetUserIdAsync(ApplicationUser user, CancellationToken cancellationToken = default)
{ {
@ -85,8 +100,10 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
return Task.FromResult(user.UserName); return Task.FromResult(user.UserName);
} }
*/
/// <inheritdoc /> /// <inheritdoc />
/*
public override async Task SetUserNameAsync(ApplicationUser user, string userName, CancellationToken cancellationToken) public override async Task SetUserNameAsync(ApplicationUser user, string userName, CancellationToken cancellationToken)
{ {
var foundUser = await _context.Users.FirstOrDefaultAsync(x => x.Id == user.Id, cancellationToken: cancellationToken); var foundUser = await _context.Users.FirstOrDefaultAsync(x => x.Id == user.Id, cancellationToken: cancellationToken);
@ -94,7 +111,9 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
foundUser.UserName = userName; foundUser.UserName = userName;
await SaveChanges(user); await SaveChanges(user);
} }
*/
/*
/// <inheritdoc /> /// <inheritdoc />
public override Task<string> GetNormalizedUserNameAsync(ApplicationUser user, CancellationToken cancellationToken) public override Task<string> GetNormalizedUserNameAsync(ApplicationUser user, CancellationToken cancellationToken)
{ {
@ -107,19 +126,6 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
} }
/// <inheritdoc />
public override async Task<IdentityResult> CreateAsync(ApplicationUser user, CancellationToken cancellationToken)
{
var u = await _context.AddAsync(user, cancellationToken);
if(u.State == EntityState.Added)
{
await SaveChanges();
return IdentityResult.Success;
}
return IdentityResult.Failed();
}
/// <inheritdoc /> /// <inheritdoc />
public override async Task<IdentityResult> UpdateAsync(ApplicationUser user, CancellationToken cancellationToken) public override async Task<IdentityResult> UpdateAsync(ApplicationUser user, CancellationToken cancellationToken)
@ -154,6 +160,7 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
var user = await db.FirstOrDefaultAsync(u => u.Id.ToString() == id); var user = await db.FirstOrDefaultAsync(u => u.Id.ToString() == id);
return user; return user;
} }
*/
/// <inheritdoc /> /// <inheritdoc />
@ -178,6 +185,7 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
return Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash)); return Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash));
} }
/*
/// <inheritdoc /> /// <inheritdoc />
public override Task<string> GetEmailAsync(ApplicationUser user, CancellationToken cancellationToken = default) public override Task<string> GetEmailAsync(ApplicationUser user, CancellationToken cancellationToken = default)
{ {
@ -220,6 +228,6 @@ public class UserRepository : UserStore<ApplicationUser, ApplicationRole, Applic
} }
return Task.FromResult(user.NormalizedEmail); return Task.FromResult(user.NormalizedEmail);
} }*/
} }

View File

@ -9,5 +9,8 @@
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"DockerMySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;" "DockerMySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;"
},
"AuthSettings": {
"SecretKey": "d123d123d123fff12"
} }
} }

View File

@ -23,6 +23,8 @@ namespace BlueWest.Data
public List<Industry> Industry { get; set; } public List<Industry> Industry { get; set; }
public DateTime CreationDate { get; set; }
} }
} }

View File

@ -16,6 +16,8 @@ namespace BlueWest.Data
public DateTime FoundingDate { get; set; } public DateTime FoundingDate { get; set; }
public DateTime CreateTime { get; } = DateTime.Now;
} }
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@ -33,6 +34,8 @@ namespace BlueWest.Data
public List<Currency> Currencies { get; set; } public List<Currency> Currencies { get; set; }
public List<User> Users { get; set; } public List<User> Users { get; set; }
public DateTime CreationDate { get; set; }
} }
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using MapTo; using MapTo;
@ -18,6 +19,7 @@ namespace BlueWest.Data
public string Alpha2Code { get; set; } public string Alpha2Code { get; set; }
public string TLD { get; set; } public string TLD { get; set; }
public DateTime CreateTime { get; } = DateTime.Now;
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using MapTo; using MapTo;
@ -16,6 +17,8 @@ namespace BlueWest.Data
public int Num { get; set; } public int Num { get; set; }
[MaxLength(3)] public string Code { get; set; } [MaxLength(3)] public string Code { get; set; }
public List<Country> Countries { get; set; } public List<Country> Countries { get; set; }
public DateTime CreateDate { get; set; }
} }
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using MapTo; using MapTo;
@ -11,6 +12,7 @@ namespace BlueWest.Data
public int Num { get; set; } // Primary key public int Num { get; set; } // Primary key
[MaxLength(3)] public string Code { get; set; } [MaxLength(3)] public string Code { get; set; }
public DateTime CreateDate { get; set; }
} }
} }

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using MapTo; using MapTo;
@ -10,6 +11,9 @@ namespace BlueWest.Data
public string IndustryName { get; set; } public string IndustryName { get; set; }
public Industry IndustryParent { get; set; } public Industry IndustryParent { get; set; }
public List<Industry> IndustryChilds { get; set; } public List<Industry> IndustryChilds { get; set; }
public DateTime CreateDate { get; set; }
} }
} }

View File

@ -1,3 +1,4 @@
using System;
using MapTo; using MapTo;
namespace BlueWest.Data namespace BlueWest.Data
@ -8,6 +9,9 @@ namespace BlueWest.Data
public int Id { get; set; } public int Id { get; set; }
public string IndustryName { get; set; } public string IndustryName { get; set; }
public Industry IndustryParent { get; set; } public Industry IndustryParent { get; set; }
public DateTime CreateDate { get; set; }
} }
} }

View File

@ -10,6 +10,7 @@ namespace BlueWest.Data
[UseUpdate] [UseUpdate]
public partial class User public partial class User
{ {
public string ApplicationUserId { get; set; }
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } public string Name { get; set; }