You need to sign in or sign up before continuing.
Commit 45a07430 authored by Almouhannad's avatar Almouhannad

(B) Add password hasher, seed user roles (and fix id bug in role)

parent 00408ab3
using Domain.Entities.Medicals.Medicines.MedicineFormValues;
using Domain.Entities.Identity.UserRoles;
using Domain.Entities.Medicals.Medicines.MedicineFormValues;
using Domain.Entities.People.Doctors.Shared.Constants.DoctorStatusValues;
using Domain.Entities.People.Employees.Relations.EmployeeFamilyMembers.FamilyRoleValues;
using Domain.Entities.People.Shared.GenderValues;
......@@ -23,6 +24,9 @@ public class SeedHelper
var seedMedicineForms = serviceScope.ServiceProvider.GetRequiredService<ISeed<MedicineForm>>();
await seedMedicineForms.Seed();
var seedUserRoles = serviceScope.ServiceProvider.GetRequiredService<ISeed<Role>>();
await seedUserRoles.Seed();
}
}
}
......@@ -10,6 +10,8 @@ public class RoleConfiguration : IEntityTypeConfiguration<Role>
{
builder.ToTable(nameof(Role));
builder.Property(role => role.Id).ValueGeneratedNever();
builder.Property(role => role.Name)
.HasMaxLength(50);
......
namespace Persistence.Identity.PasswordsHashing;
public interface IPasswordHasher
{
public string Hash(string password);
public bool Verify(string password, string passwordHash);
}
using System.Security.Cryptography;
namespace Persistence.Identity.PasswordsHashing;
public class PasswordHasher : IPasswordHasher
{
#region Hashing
// Salting is adding a random number to the hash
// to ensure that users with same passwords have
// different hash values.
// Best pactice is to use 128 bits = 16 bytes
private const int SaltSize = 16;
// Output size
// Best practice is to use 256 bits
private const int HashSize = 32;
private const int Iterations = 100000;
private readonly HashAlgorithmName Algorithm = HashAlgorithmName.SHA512;
public string Hash(string password)
{
byte[] salt = RandomNumberGenerator.GetBytes(SaltSize);
byte[] hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, Algorithm, HashSize);
// Pdkdf ~ Password Based Key Derivation Function
return $"{Convert.ToHexString(hash)}-{Convert.ToHexString(salt)}";
}
#endregion
#region Verification
public bool Verify(string password, string passwordHash)
{
string[] parts = passwordHash.Split('-');
byte[] hash = Convert.FromHexString(parts[0]);
byte[] salt = Convert.FromHexString(parts[1]);
byte[] inputHash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, Algorithm, HashSize);
return CryptographicOperations.FixedTimeEquals(hash, inputHash);
}
#endregion
}
......@@ -12,7 +12,7 @@ using Persistence.Context;
namespace Persistence.Migrations
{
[DbContext(typeof(ClinicsDbContext))]
[Migration("20240820202107_Add_Identity")]
[Migration("20240820212742_Add_Identity")]
partial class Add_Identity
{
/// <inheritdoc />
......@@ -28,11 +28,8 @@ namespace Persistence.Migrations
modelBuilder.Entity("Domain.Entities.Identity.UserRoles.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
......
......@@ -14,8 +14,7 @@ namespace Persistence.Migrations
name: "Role",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Id = table.Column<int>(type: "int", nullable: false),
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false)
},
constraints: table =>
......
......@@ -25,11 +25,8 @@ namespace Persistence.Migrations
modelBuilder.Entity("Domain.Entities.Identity.UserRoles.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
......
using Domain.Entities.Identity.UserRoles;
using Microsoft.EntityFrameworkCore;
using Persistence.Context;
namespace Persistence.SeedDatabase;
public class UserRoles : ISeed<Role>
{
#region CTOR DI
private readonly ClinicsDbContext _context;
public UserRoles(ClinicsDbContext context)
{
_context = context;
}
#endregion
public async Task Seed()
{
DbSet<Role> roles = _context.Set<Role>();
var current = await roles.ToListAsync();
// TODO: perform deep check on all seed operations
if (current.Count != Roles.Count)
{
roles.RemoveRange(current);
roles.Add(Roles.Admin);
roles.Add(Roles.Doctor);
roles.Add(Roles.Receptionist);
await _context.SaveChangesAsync();
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment