Пример #1
0
        public async Task <IActionResult> RefreshTokenExchangeAsync([FromBody] RefreshTokenViewModel refreshTokenData)
        {
            _logger.LogInformation($"Starting method '{nameof(RefreshTokenExchangeAsync)}'.");

            try
            {
                _logger.LogDebug($"Getting principal from passed access token.");
                var claims = _jwtTokenHandler.GetPrincipalFromJwtToken(refreshTokenData.AccessToken, true);

                // Get expiry date of the access token. If it's not before UtcNow then return 400 BadRequest.
                var expiryDate = DateTimeOffset.FromUnixTimeSeconds(int.Parse(claims.FindFirstValue(JwtRegisteredClaimNames.Exp)));
                if (expiryDate.DateTime > DateTime.UtcNow)
                {
                    return(OnInvalidParameterError($"The access token passed has not expired."));
                }

                // Check if passed refresh token matches any saved refresh token.
                _logger.LogDebug("Checking refresh token correctness.");
                var savedRefreshToken = await _refreshTokenManager.GetSavedRefreshTokenAsync(refreshTokenData.RefreshToken);

                // Check if refresh token expired.
                if (IsRefreshTokenExpired(savedRefreshToken))
                {
                    return(OnInvalidParameterError($"The refresh token passed has expired."));
                }

                // Create temporary user representation based on access token principal.
                var tempUser = new IdentityUser
                {
                    Id       = claims.FindFirstValue(JwtRegisteredClaimNames.NameId),
                    UserName = claims.FindFirstValue(JwtRegisteredClaimNames.Sub),
                    Email    = claims.FindFirstValue(JwtRegisteredClaimNames.Email)
                };

                string[] userRoles = new string[] { claims.FindFirstValue(ApiConstants.RoleClaim) };

                // Generate new access and refresh tokens.
                _logger.LogDebug("Generating new access and refresh tokens.");
                var    newJwtToken     = _jwtTokenHandler.CreateJwtToken(tempUser, userRoles);
                string newAccessToken  = _jwtTokenHandler.WriteJwtToken(newJwtToken);
                var    newRefreshToken = _refreshTokenManager.GenerateRefreshToken();

                // Add new refresh token to the database for future tokens exchange.
                // Delete the saved token to prevent the use of the refresh token more than once.
                _logger.LogDebug("Adding new refresh token to the database.");
                await _refreshTokenManager.AddRefreshTokenAsync(newRefreshToken);

                _logger.LogDebug("Deleting saved refresh token from the database.");
                await _refreshTokenManager.DeleteRefreshTokenAsync(savedRefreshToken);

                var response = new ResponseWrapper(new RefreshTokensResponseDto
                {
                    AccessToken  = new AccessToken(newAccessToken, (int)newJwtToken.Payload.Exp),
                    RefreshToken = MapToDto(newRefreshToken)
                });

                _logger.LogInformation($"Finished method '{nameof(RefreshTokenExchangeAsync)}'.");
                return(Ok(response));
            }
            catch (InvalidOperationException ex)
            {
                return(OnInvalidParameterError($"Invalid refresh token.", ex));
            }
            catch (SecurityTokenException ex)
            {
                return(OnInvalidParameterError($"Invalid access token.", ex));
            }
            catch (Exception ex)
            {
                LogUnexpectedException(ex, ex.Message);
                throw;
            }
        }