diff options
author | crupest <crupest@outlook.com> | 2020-11-26 23:43:11 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-11-26 23:43:11 +0800 |
commit | c2ca954fc8bc0f12ad2ece715cb6c4a633a23119 (patch) | |
tree | e095e0583b927472d04af4e9546a7e78277a04d2 /BackEnd/Timeline/Services/UserCredentialService.cs | |
parent | 43ac8b704e47e05d259f35d0a9cdb4de6c787ee5 (diff) | |
download | timeline-c2ca954fc8bc0f12ad2ece715cb6c4a633a23119.tar.gz timeline-c2ca954fc8bc0f12ad2ece715cb6c4a633a23119.tar.bz2 timeline-c2ca954fc8bc0f12ad2ece715cb6c4a633a23119.zip |
refactor: ...
Diffstat (limited to 'BackEnd/Timeline/Services/UserCredentialService.cs')
-rw-r--r-- | BackEnd/Timeline/Services/UserCredentialService.cs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/BackEnd/Timeline/Services/UserCredentialService.cs b/BackEnd/Timeline/Services/UserCredentialService.cs new file mode 100644 index 00000000..e5c3581b --- /dev/null +++ b/BackEnd/Timeline/Services/UserCredentialService.cs @@ -0,0 +1,104 @@ +using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Timeline.Entities;
+using Timeline.Helpers;
+using Timeline.Models;
+using Timeline.Models.Validation;
+using Timeline.Services.Exceptions;
+
+namespace Timeline.Services
+{
+ public interface IUserCredentialService
+ {
+ /// <summary>
+ /// Try to verify the given username and password.
+ /// </summary>
+ /// <param name="username">The username of the user to verify.</param>
+ /// <param name="password">The password of the user to verify.</param>
+ /// <returns>User id.</returns>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format or <paramref name="password"/> is empty.</exception>
+ /// <exception cref="UserNotExistException">Thrown when the user with given username does not exist.</exception>
+ /// <exception cref="BadPasswordException">Thrown when password is wrong.</exception>
+ Task<long> VerifyCredential(string username, string password);
+
+ /// <summary>
+ /// Try to change a user's password with old password.
+ /// </summary>
+ /// <param name="id">The id of user to change password of.</param>
+ /// <param name="oldPassword">Old password.</param>
+ /// <param name="newPassword">New password.</param>
+ /// <exception cref="ArgumentNullException">Thrown if <paramref name="oldPassword"/> or <paramref name="newPassword"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown if <paramref name="oldPassword"/> or <paramref name="newPassword"/> is empty.</exception>
+ /// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception>
+ /// <exception cref="BadPasswordException">Thrown if the old password is wrong.</exception>
+ Task ChangePassword(long id, string oldPassword, string newPassword);
+ }
+
+ public class UserCredentialService : IUserCredentialService
+ {
+ private readonly ILogger<UserCredentialService> _logger;
+ private readonly DatabaseContext _database;
+ private readonly IPasswordService _passwordService;
+
+ private readonly UsernameValidator _usernameValidator = new UsernameValidator();
+
+ public UserCredentialService(ILogger<UserCredentialService> logger, DatabaseContext database, IPasswordService passwordService)
+ {
+ _logger = logger;
+ _database = database;
+ _passwordService = passwordService;
+ }
+
+ public async Task<long> VerifyCredential(string username, string password)
+ {
+ if (username == null)
+ throw new ArgumentNullException(nameof(username));
+ if (password == null)
+ throw new ArgumentNullException(nameof(password));
+ if (!_usernameValidator.Validate(username, out var message))
+ throw new ArgumentException(message);
+ if (password.Length == 0)
+ throw new ArgumentException("Password can't be empty.");
+
+ var entity = await _database.Users.Where(u => u.Username == username).Select(u => new { u.Id, u.Password }).SingleOrDefaultAsync();
+
+ if (entity == null)
+ throw new UserNotExistException(username);
+
+ if (!_passwordService.VerifyPassword(entity.Password, password))
+ throw new BadPasswordException(password);
+
+ return entity.Id;
+ }
+
+ public async Task ChangePassword(long id, string oldPassword, string newPassword)
+ {
+ if (oldPassword == null)
+ throw new ArgumentNullException(nameof(oldPassword));
+ if (newPassword == null)
+ throw new ArgumentNullException(nameof(newPassword));
+ if (oldPassword.Length == 0)
+ throw new ArgumentException("Old password can't be empty.");
+ if (newPassword.Length == 0)
+ throw new ArgumentException("New password can't be empty.");
+
+ var entity = await _database.Users.Where(u => u.Id == id).SingleOrDefaultAsync();
+
+ if (entity == null)
+ throw new UserNotExistException(id);
+
+ if (!_passwordService.VerifyPassword(entity.Password, oldPassword))
+ throw new BadPasswordException(oldPassword);
+
+ entity.Password = _passwordService.HashPassword(newPassword);
+ entity.Version += 1;
+ await _database.SaveChangesAsync();
+ _logger.LogInformation(Log.Format(Resources.Services.UserService.LogDatabaseUpdate, ("Id", id), ("Operation", "Change password")));
+ }
+ }
+}
|