From c2ca954fc8bc0f12ad2ece715cb6c4a633a23119 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 26 Nov 2020 23:43:11 +0800 Subject: refactor: ... --- .../Services/HighlightTimelineServiceTest.cs | 6 +- BackEnd/Timeline/Controllers/TokenController.cs | 4 +- BackEnd/Timeline/Controllers/UserController.cs | 6 +- BackEnd/Timeline/Services/TimelinePostService.cs | 4 +- BackEnd/Timeline/Services/TimelineService.cs | 3 - BackEnd/Timeline/Services/UserCredentialService.cs | 104 +++++++++++++++++++++ BackEnd/Timeline/Services/UserService.cs | 68 -------------- BackEnd/Timeline/Services/UserTokenManager.cs | 7 +- BackEnd/Timeline/Startup.cs | 2 +- 9 files changed, 120 insertions(+), 84 deletions(-) create mode 100644 BackEnd/Timeline/Services/UserCredentialService.cs (limited to 'BackEnd') diff --git a/BackEnd/Timeline.Tests/Services/HighlightTimelineServiceTest.cs b/BackEnd/Timeline.Tests/Services/HighlightTimelineServiceTest.cs index 950fa974..a4cd983d 100644 --- a/BackEnd/Timeline.Tests/Services/HighlightTimelineServiceTest.cs +++ b/BackEnd/Timeline.Tests/Services/HighlightTimelineServiceTest.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Timeline.Services; +using Timeline.Services; namespace Timeline.Tests.Services { diff --git a/BackEnd/Timeline/Controllers/TokenController.cs b/BackEnd/Timeline/Controllers/TokenController.cs index 8f2ca600..41ec21e6 100644 --- a/BackEnd/Timeline/Controllers/TokenController.cs +++ b/BackEnd/Timeline/Controllers/TokenController.cs @@ -22,6 +22,7 @@ namespace Timeline.Controllers [ProducesErrorResponseType(typeof(CommonResponse))] public class TokenController : Controller { + private readonly IUserCredentialService _userCredentialService; private readonly IUserTokenManager _userTokenManager; private readonly ILogger _logger; private readonly IClock _clock; @@ -29,8 +30,9 @@ namespace Timeline.Controllers private readonly IMapper _mapper; /// - public TokenController(IUserTokenManager userTokenManager, ILogger logger, IClock clock, IMapper mapper) + public TokenController(IUserCredentialService userCredentialService, IUserTokenManager userTokenManager, ILogger logger, IClock clock, IMapper mapper) { + _userCredentialService = userCredentialService; _userTokenManager = userTokenManager; _logger = logger; _clock = clock; diff --git a/BackEnd/Timeline/Controllers/UserController.cs b/BackEnd/Timeline/Controllers/UserController.cs index 8edae139..626a116f 100644 --- a/BackEnd/Timeline/Controllers/UserController.cs +++ b/BackEnd/Timeline/Controllers/UserController.cs @@ -26,15 +26,17 @@ namespace Timeline.Controllers { private readonly ILogger _logger; private readonly IUserService _userService; + private readonly IUserCredentialService _userCredentialService; private readonly IUserPermissionService _userPermissionService; private readonly IUserDeleteService _userDeleteService; private readonly IMapper _mapper; /// - public UserController(ILogger logger, IUserService userService, IUserPermissionService userPermissionService, IUserDeleteService userDeleteService, IMapper mapper) + public UserController(ILogger logger, IUserService userService, IUserCredentialService userCredentialService, IUserPermissionService userPermissionService, IUserDeleteService userDeleteService, IMapper mapper) { _logger = logger; _userService = userService; + _userCredentialService = userCredentialService; _userPermissionService = userPermissionService; _userDeleteService = userDeleteService; _mapper = mapper; @@ -190,7 +192,7 @@ namespace Timeline.Controllers { try { - await _userService.ChangePassword(this.GetUserId(), request.OldPassword, request.NewPassword); + await _userCredentialService.ChangePassword(this.GetUserId(), request.OldPassword, request.NewPassword); return Ok(); } catch (BadPasswordException e) diff --git a/BackEnd/Timeline/Services/TimelinePostService.cs b/BackEnd/Timeline/Services/TimelinePostService.cs index 36fcdbca..a1176a68 100644 --- a/BackEnd/Timeline/Services/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/TimelinePostService.cs @@ -1,4 +1,6 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using SixLabors.ImageSharp; using System; using System.Collections.Generic; using System.Globalization; @@ -8,9 +10,7 @@ using Timeline.Entities; using Timeline.Helpers; using Timeline.Models; using Timeline.Services.Exceptions; -using SixLabors.ImageSharp; using static Timeline.Resources.Services.TimelineService; -using Microsoft.Extensions.Logging; namespace Timeline.Services { diff --git a/BackEnd/Timeline/Services/TimelineService.cs b/BackEnd/Timeline/Services/TimelineService.cs index f943f8b4..b8ec354a 100644 --- a/BackEnd/Timeline/Services/TimelineService.cs +++ b/BackEnd/Timeline/Services/TimelineService.cs @@ -1,13 +1,10 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using SixLabors.ImageSharp; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; using Timeline.Entities; -using Timeline.Helpers; using Timeline.Models; using Timeline.Models.Validation; using Timeline.Services.Exceptions; 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 + { + /// + /// Try to verify the given username and password. + /// + /// The username of the user to verify. + /// The password of the user to verify. + /// User id. + /// Thrown when or is null. + /// Thrown when is of bad format or is empty. + /// Thrown when the user with given username does not exist. + /// Thrown when password is wrong. + Task VerifyCredential(string username, string password); + + /// + /// Try to change a user's password with old password. + /// + /// The id of user to change password of. + /// Old password. + /// New password. + /// Thrown if or is null. + /// Thrown if or is empty. + /// Thrown if the user with given username does not exist. + /// Thrown if the old password is wrong. + Task ChangePassword(long id, string oldPassword, string newPassword); + } + + public class UserCredentialService : IUserCredentialService + { + private readonly ILogger _logger; + private readonly DatabaseContext _database; + private readonly IPasswordService _passwordService; + + private readonly UsernameValidator _usernameValidator = new UsernameValidator(); + + public UserCredentialService(ILogger logger, DatabaseContext database, IPasswordService passwordService) + { + _logger = logger; + _database = database; + _passwordService = passwordService; + } + + public async Task 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"))); + } + } +} diff --git a/BackEnd/Timeline/Services/UserService.cs b/BackEnd/Timeline/Services/UserService.cs index cded3ff1..9395cc52 100644 --- a/BackEnd/Timeline/Services/UserService.cs +++ b/BackEnd/Timeline/Services/UserService.cs @@ -26,19 +26,6 @@ namespace Timeline.Services public interface IUserService : IBasicUserService { - /// - /// Try to verify the given username and password. - /// - /// The username of the user to verify. - /// The password of the user to verify. - /// The user info and auth info. - /// Thrown when or is null. - /// Thrown when is of bad format or is empty. - /// Thrown when the user with given username does not exist. - /// Thrown when password is wrong. - Task VerifyCredential(string username, string password); - - /// /// Try to get a user by id. /// @@ -47,7 +34,6 @@ namespace Timeline.Services /// Thrown when the user with given id does not exist. Task GetUser(long id); - /// /// List all users. /// @@ -77,18 +63,6 @@ namespace Timeline.Services /// Version will increase if password is changed. /// Task ModifyUser(long id, ModifyUserParams? param); - - /// - /// Try to change a user's password with old password. - /// - /// The id of user to change password of. - /// Old password. - /// New password. - /// Thrown if or is null. - /// Thrown if or is empty. - /// Thrown if the user with given username does not exist. - /// Thrown if the old password is wrong. - Task ChangePassword(long id, string oldPassword, string newPassword); } public class UserService : BasicUserService, IUserService @@ -159,26 +133,7 @@ namespace Timeline.Services }; } - public async Task VerifyCredential(string username, string password) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - if (password == null) - throw new ArgumentNullException(nameof(password)); - - CheckUsernameFormat(username, nameof(username)); - CheckPasswordFormat(password, nameof(password)); - - var entity = await _databaseContext.Users.Where(u => u.Username == username).SingleOrDefaultAsync(); - - if (entity == null) - throw new UserNotExistException(username); - if (!_passwordService.VerifyPassword(entity.Password, password)) - throw new BadPasswordException(password); - - return await CreateUserFromEntity(entity); - } public async Task GetUser(long id) { @@ -288,28 +243,5 @@ namespace Timeline.Services return await CreateUserFromEntity(entity); } - - 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)); - CheckPasswordFormat(oldPassword, nameof(oldPassword)); - CheckPasswordFormat(newPassword, nameof(newPassword)); - - var entity = await _databaseContext.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 _databaseContext.SaveChangesAsync(); - _logger.LogInformation(Log.Format(LogDatabaseUpdate, ("Id", id), ("Operation", "Change password"))); - } } } diff --git a/BackEnd/Timeline/Services/UserTokenManager.cs b/BackEnd/Timeline/Services/UserTokenManager.cs index 09ecd19c..831329e6 100644 --- a/BackEnd/Timeline/Services/UserTokenManager.cs +++ b/BackEnd/Timeline/Services/UserTokenManager.cs @@ -45,13 +45,15 @@ namespace Timeline.Services { private readonly ILogger _logger; private readonly IUserService _userService; + private readonly IUserCredentialService _userCredentialService; private readonly IUserTokenService _userTokenService; private readonly IClock _clock; - public UserTokenManager(ILogger logger, IUserService userService, IUserTokenService userTokenService, IClock clock) + public UserTokenManager(ILogger logger, IUserService userService, IUserCredentialService userCredentialService, IUserTokenService userTokenService, IClock clock) { _logger = logger; _userService = userService; + _userCredentialService = userCredentialService; _userTokenService = userTokenService; _clock = clock; } @@ -65,7 +67,8 @@ namespace Timeline.Services if (password == null) throw new ArgumentNullException(nameof(password)); - var user = await _userService.VerifyCredential(username, password); + var userId = await _userCredentialService.VerifyCredential(username, password); + var user = await _userService.GetUser(userId); var token = _userTokenService.GenerateToken(new UserTokenInfo { Id = user.Id, Version = user.Version, ExpireAt = expireAt }); return new UserTokenCreateResult { Token = token, User = user }; diff --git a/BackEnd/Timeline/Startup.cs b/BackEnd/Timeline/Startup.cs index 63e2a0dd..bf34f9e2 100644 --- a/BackEnd/Timeline/Startup.cs +++ b/BackEnd/Timeline/Startup.cs @@ -90,6 +90,7 @@ namespace Timeline services.AddTransient(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -100,7 +101,6 @@ namespace Timeline services.AddScoped(); services.AddScoped(); - services.AddDbContext((services, options) => { var pathProvider = services.GetRequiredService(); -- cgit v1.2.3