aboutsummaryrefslogtreecommitdiff
path: root/BackEnd/Timeline/Services/Token/UserTokenManager.cs
blob: bdb229f0e873c835e805fc507386179cd077f949 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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.User;

namespace Timeline.Services.Token
{
    public class UserTokenManager : IUserTokenManager
    {
        private readonly ILogger<UserTokenManager> _logger;
        private readonly IOptionsMonitor<TokenOptions> _tokenOptionsMonitor;
        private readonly IUserService _userService;
        private readonly IUserTokenHandler _userTokenService;
        private readonly IClock _clock;

        public UserTokenManager(ILogger<UserTokenManager> logger, IOptionsMonitor<TokenOptions> tokenOptionsMonitor, IUserService userService, IUserTokenHandler userTokenService, IClock clock)
        {
            _logger = logger;
            _tokenOptionsMonitor = tokenOptionsMonitor;
            _userService = userService;
            _userTokenService = userTokenService;
            _clock = clock;
        }

        public async Task<UserTokenCreateResult> CreateTokenAsync(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 _userService.VerifyCredential(username, password);
            var user = await _userService.GetUserAsync(userId);

            var token = await _userTokenService.GenerateTokenAsync(new UserTokenInfo
            {
                Id = user.Id,
                Version = user.Version,
                ExpireAt = expireAt ?? _clock.GetCurrentTime() + TimeSpan.FromSeconds(_tokenOptionsMonitor.CurrentValue.DefaultExpireSeconds)
            });

            _logger.LogInformation(Resource.LogTokenCreate, user.Username, userId);

            return new UserTokenCreateResult { Token = token, User = user };
        }


        public async Task<UserEntity> VerifyTokenAsync(string token)
        {
            if (token == null)
                throw new ArgumentNullException(nameof(token));

            UserTokenInfo tokenInfo;

            try
            {
                tokenInfo = await _userTokenService.ValidateTokenAsync(token);
            }
            catch (UserTokenBadFormatException e)
            {
                _logger.LogInformation(e, Resource.LogTokenVerifiedFail);
                throw;
            }

            var currentTime = _clock.GetCurrentTime();
            if (tokenInfo.ExpireAt < currentTime)
            {
                var e = new UserTokenTimeExpiredException(token, tokenInfo.ExpireAt, currentTime);
                _logger.LogInformation(e, Resource.LogTokenVerifiedFail);
                throw e;
            }

            try
            {
                var user = await _userService.GetUserAsync(tokenInfo.Id);

                if (tokenInfo.Version < user.Version)
                {
                    var e = new UserTokenVersionExpiredException(token, tokenInfo.Version, user.Version);
                    _logger.LogInformation(e, Resource.LogTokenVerifiedFail);
                    throw e;
                }

                _logger.LogInformation(Resource.LogTokenVerified, user.Username, user.Id);

                return user;
            }
            catch (EntityNotExistException e)
            {
                var exception = new UserTokenUserNotExistException(token, e);
                _logger.LogInformation(exception, Resource.LogTokenVerifiedFail);
                throw exception;
            }
        }
    }
}