You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LuUsersBusiness.cs 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Security.Cryptography;
  4. using System.Text;
  5. using Luticate2.Auth.DataAccess;
  6. using Luticate2.Auth.Dbo.Users;
  7. using Luticate2.Auth.Interfaces.Tokens;
  8. using Luticate2.Auth.Interfaces.Users;
  9. using Luticate2.Utils.Business;
  10. using Luticate2.Utils.Dbo.Result;
  11. using Luticate2.Utils.Interfaces;
  12. using Luticate2.Utils.Utils;
  13. using Microsoft.AspNetCore.Cryptography.KeyDerivation;
  14. namespace Luticate2.Auth.Business
  15. {
  16. public class LuUsersBusiness : LuCrudBusiness<LuUsersDataAccess, LuUsersAddFullDbo, LuUsersFullDbo, LuUsersEditFullDbo, string>, ILuUsersBusiness
  17. {
  18. private readonly ILuTokensBusiness _luTokensBusiness;
  19. private readonly ILuLoggedUserAccessor _luLoggedUserAccessor;
  20. public LuUsersBusiness(LuUsersDataAccess dataAccess, ILuNotificationsBusiness notificationsBusiness,
  21. ILuTokensBusiness luTokensBusiness, ILuLoggedUserAccessor luLoggedUserAccessor) : base(dataAccess, notificationsBusiness)
  22. {
  23. _luTokensBusiness = luTokensBusiness;
  24. _luLoggedUserAccessor = luLoggedUserAccessor;
  25. }
  26. public string GenerateSalt()
  27. {
  28. var salt = new byte[128 / 8];
  29. using (var rng = RandomNumberGenerator.Create())
  30. {
  31. rng.GetBytes(salt);
  32. }
  33. return Convert.ToBase64String(salt);
  34. }
  35. public string HashPassword(string password, string salt)
  36. {
  37. var hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(password, Encoding.ASCII.GetBytes(salt),
  38. KeyDerivationPrf.HMACSHA1, 10000, 256 / 8));
  39. return hashed;
  40. }
  41. public bool VerifyPasswordHash(string password, string hash, string salt)
  42. {
  43. var newHash = HashPassword(password, salt);
  44. return newHash == hash;
  45. }
  46. public LuResult<LuUsersFullDbo> FindByUsername(string username)
  47. {
  48. return DataAccess.FindByUsername(username);
  49. }
  50. public LuResult<LuUsersFullDbo> Register(LuUsersAddDbo user)
  51. {
  52. var userRes = FindByUsername(user.Username);
  53. if (userRes)
  54. {
  55. return LuResult<LuUsersFullDbo>.Error(LuStatus.InputError,
  56. $"username: {user.Username}", "Username already exists");
  57. }
  58. if (userRes.Status != LuStatus.NotFound)
  59. {
  60. return userRes;
  61. }
  62. var salt = GenerateSalt();
  63. var password = HashPassword(user.Password, salt);
  64. return this.AddDbo(new LuUsersAddFullDbo
  65. {
  66. AuthenticationSourceId = Guid.Empty.ToDbo(),
  67. Data = null,
  68. Password = password,
  69. Salt = salt,
  70. Username = user.Username
  71. });
  72. }
  73. public LuResult<LuUsersFullDbo> Edit(string id, LuUsersEditDbo user)
  74. {
  75. throw new NotImplementedException();
  76. }
  77. public LuResult<LuUsersLoginResultDbo> Login(string username, string password)
  78. {
  79. var userRes = FindByUsername(username);
  80. if (userRes.Status == LuStatus.NotFound)
  81. {
  82. return LuResult<LuUsersLoginResultDbo>.Error(LuStatus.LoginError,
  83. $"unknown username; username: {username}", "Invalid username or password");
  84. }
  85. if (!userRes)
  86. {
  87. return userRes.To<LuUsersLoginResultDbo>();
  88. }
  89. if (userRes.Data.Password == null)
  90. {
  91. return LuResult<LuUsersLoginResultDbo>.Error(LuStatus.LoginError,
  92. $"null password; username: {username}", "Invalid username or password");
  93. }
  94. if (!VerifyPasswordHash(password, userRes.Data.Password, userRes.Data.Salt))
  95. {
  96. return LuResult<LuUsersLoginResultDbo>.Error(LuStatus.LoginError,
  97. $"invalid password; username: {username}", "Invalid username or password");
  98. }
  99. var tokenRes = _luTokensBusiness.GenerateToken(userRes.Data.ToLite());
  100. if (!tokenRes)
  101. {
  102. return tokenRes.To<LuUsersLoginResultDbo>();
  103. }
  104. return LuResult<LuUsersLoginResultDbo>.Ok(new LuUsersLoginResultDbo
  105. {
  106. Token = tokenRes.Data,
  107. User = userRes.Data.ToLite()
  108. });
  109. }
  110. public LuResult<bool> Logout(string token)
  111. {
  112. if (token == null)
  113. {
  114. return LuResult<bool>.Ok(true);
  115. }
  116. return _luTokensBusiness.UnRegisterToken(token).To(usersToken => true);
  117. }
  118. public LuResult<LuUsersFullDbo> Me()
  119. {
  120. return LuResult<LuUsersFullDbo>.Ok(_luLoggedUserAccessor.GetLoggedUser());
  121. }
  122. LuResult<T> ILuCrudInterface<LuUsersAddFullDbo, LuUsersFullDbo, LuUsersEditFullDbo, string>.DeleteSingleById<T>(string id, Func<LuUsersFullDbo, T> returnFunc)
  123. {
  124. var loggedUser = _luLoggedUserAccessor.GetLoggedUser();
  125. if (id == Guid.Empty.ToDbo())
  126. {
  127. return LuResult<T>.Error(LuStatus.InputError,
  128. $"loggedUser: {loggedUser.Username}", "Can not remove anonymous user");
  129. }
  130. if (id == loggedUser.Id)
  131. {
  132. return LuResult<T>.Error(LuStatus.InputError,
  133. $"loggedUser: {loggedUser.Username}", "Can not remove yourself");
  134. }
  135. return base.DeleteSingleById(id, returnFunc);
  136. }
  137. }
  138. }