From 7c37a5885437aaf97b9986b7cc2941b5e4316003 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 24 Apr 2021 22:01:27 +0800 Subject: refactor: Move token services. --- .../Timeline/Services/Token/UserTokenManager.cs | 115 +++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 BackEnd/Timeline/Services/Token/UserTokenManager.cs (limited to 'BackEnd/Timeline/Services/Token/UserTokenManager.cs') diff --git a/BackEnd/Timeline/Services/Token/UserTokenManager.cs b/BackEnd/Timeline/Services/Token/UserTokenManager.cs new file mode 100644 index 00000000..00bc2cf7 --- /dev/null +++ b/BackEnd/Timeline/Services/Token/UserTokenManager.cs @@ -0,0 +1,115 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using Timeline.Configs; +using Timeline.Entities; +using Timeline.Helpers; +using Timeline.Services.Exceptions; + +namespace Timeline.Services.Token +{ + public class UserTokenCreateResult + { + public string Token { get; set; } = default!; + public UserEntity User { get; set; } = default!; + } + + public interface IUserTokenManager + { + /// + /// Try to create a token for given username and password. + /// + /// The username. + /// The password. + /// The expire time of the token. + /// The created token and the user info. + /// Thrown when or is null. + /// Thrown when is of bad format. + /// Thrown when the user with does not exist. + /// Thrown when is wrong. + public Task CreateToken(string username, string password, DateTime? expireAt = null); + + /// + /// Verify a token and get the saved user info. This also check the database for existence of the user. + /// + /// The token. + /// The user stored in token. + /// Thrown when is null. + /// Thrown when the token is expired. + /// Thrown when the token is of bad version. + /// Thrown when the token is of bad format. + /// Thrown when the user specified by the token does not exist. Usually the user had been deleted after the token was issued. + public Task VerifyToken(string token); + } + + public class UserTokenManager : IUserTokenManager + { + private readonly ILogger _logger; + private readonly IOptionsMonitor _tokenOptionsMonitor; + private readonly IUserService _userService; + private readonly IUserCredentialService _userCredentialService; + private readonly IUserTokenHandler _userTokenService; + private readonly IClock _clock; + + public UserTokenManager(ILogger logger, IOptionsMonitor tokenOptionsMonitor, IUserService userService, IUserCredentialService userCredentialService, IUserTokenHandler userTokenService, IClock clock) + { + _logger = logger; + _tokenOptionsMonitor = tokenOptionsMonitor; + _userService = userService; + _userCredentialService = userCredentialService; + _userTokenService = userTokenService; + _clock = clock; + } + + public async Task CreateToken(string username, string password, DateTime? expireAt = null) + { + expireAt = expireAt?.MyToUtc(); + + if (username == null) + throw new ArgumentNullException(nameof(username)); + if (password == null) + throw new ArgumentNullException(nameof(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 ?? _clock.GetCurrentTime() + TimeSpan.FromSeconds(_tokenOptionsMonitor.CurrentValue.DefaultExpireSeconds) + }); + + return new UserTokenCreateResult { Token = token, User = user }; + } + + + public async Task VerifyToken(string token) + { + if (token == null) + throw new ArgumentNullException(nameof(token)); + + var tokenInfo = _userTokenService.VerifyToken(token); + + var currentTime = _clock.GetCurrentTime(); + if (tokenInfo.ExpireAt < currentTime) + throw new UserTokenTimeExpiredException(token, tokenInfo.ExpireAt, currentTime); + + try + { + var user = await _userService.GetUser(tokenInfo.Id); + + if (tokenInfo.Version < user.Version) + throw new UserTokenVersionExpiredException(token, tokenInfo.Version, user.Version); + + return user; + + } + catch (UserNotExistException e) + { + throw new UserTokenUserNotExistException(token, e); + } + } + } +} -- cgit v1.2.3