public async Task <OperateResult> UpdateStepAsync(int stepNum, UpdateStepUser userInfo, CancellationToken cancellationToken = default)
        {
            try
            {
                CheckValue.NotNullOrWhiteSpace(userInfo.UserKeyInfo, "userInfo.UserKeyInfo");

                var user = await _userRepo.FindByUserKeyInfoAsync(userInfo.UserKeyInfo, StepFlyProviderType.XiaoMi) ??
                           throw new SoftlyMiCakeException("在修改步数的时候没有找到对应的用户信息");

                // 刷新Token
                await TryRelogin(user, cancellationToken);

                var httpClient = _httpClientFactory.CreateClient();
                var url        = XiaoMiConfig.GetChangeStepUrl();

                var jsonOptions = new JsonSerializerOptions()
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                };
                var content = new StringContent(XiaoMiConfig.GetChangeStepRequestBody(user.UserSystemId, stepNum.ToString()), Encoding.UTF8, "application/x-www-form-urlencoded");
                content.Headers.Add("apptoken", user.TokenInfo);

                using var response = await httpClient.PostAsync(url, content, cancellationToken);

                var responseContent = await response.Content.ReadAsStringAsync();

                _logger.LogInformation(await content.ReadAsStringAsync());
                _logger.LogInformation(responseContent);

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    return(OperateResult.Failed(null, response.StatusCode.ToString(), "修改步数失败", responseContent));
                }

                using var jsonDoc = JsonDocument.Parse(responseContent);
                var successCode = jsonDoc.RootElement.GetProperty("code").GetRawText();
                if (successCode.Equals("1"))
                {
                    return(OperateResult.Success(HttpStatusCode.OK.ToString(), "修改步数成功", responseContent));
                }

                if (successCode.Equals("0"))
                {
                    return(OperateResult.Failed(null, HttpStatusCode.Unauthorized.ToString(), "修改步数失败,登录信息已经过期"));
                }

                return(OperateResult.Success(HttpStatusCode.OK.ToString(), "修改步数失败", responseContent));
            }
            catch (Exception ex)
            {
                return(OperateResult.Failed(ex, "尝试修改步数时产生错误", ex.Message));
            }
        }
        private async Task TryRelogin(StepFlyUser user, CancellationToken cancellationToken)
        {
            var needRefresh = user.TokenExpireTime < DateTime.Now;

            if (!needRefresh)
            {
                return;
            }

            var httpClient = _httpClientFactory.CreateClient("noRedirect");

            var content = new StringContent(XiaoMiConfig.GetReLoginRequestBody(user.AdditionalInfo, HttpUtility.UrlEncode(user.DeviceId, Encoding.UTF8)), Encoding.UTF8, "application/x-www-form-urlencoded");

            //add important headers
            content.Headers.Add("hm-privacy-diagnostics", "false");
            content.Headers.Add("app_name", "com.xiaomi.hm.health");
            content.Headers.Add("hm-privacy-ceip", "true");
            content.Headers.Add("X-Request-Id", Guid.NewGuid().ToString());

            try
            {
                using var response = await httpClient.PostAsync(XiaoMiConfig.ReLoginUrl, content, cancellationToken);

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    return;
                }

                var responseContent = await response.Content.ReadAsStringAsync();

                _logger.LogInformation($"ReloginResponse Content: {responseContent}");

                //得到当前登录成功的用户信息
                var successModel = JsonSerializer.Deserialize <XiaoMiReLoginSuccessModel>(responseContent, new JsonSerializerOptions()
                {
                    IgnoreNullValues = true
                });
                if (string.IsNullOrEmpty(successModel.token_info?.app_token))
                {
                    return;
                }

                //更新用户的Token信息
                user.SetToken(successModel.token_info.app_token, DateTime.Now.AddDays(invalidHours));
                user.SetAdditionalInfo(successModel.token_info.login_token);
            }
            catch
            {
                return;
            }
        }
        private async Task <OperateResult> Login(XiaoMiLoginModel loginInfo, StepFlyUser user, CancellationToken cancellationToken)
        {
            try
            {
                CheckValue.NotNullOrWhiteSpace(loginInfo.UserPhone, nameof(loginInfo.UserPhone));
                CheckValue.NotNullOrWhiteSpace(loginInfo.Password, nameof(loginInfo.Password));

                var httpClient = _httpClientFactory.CreateClient("noRedirect");

                //Step one : Get AccessToken
                var accessUrl = XiaoMiConfig.GetAccessUrl(loginInfo.UserPhone);

                var content = new StringContent(XiaoMiConfig.GetAccessRequestBody(loginInfo.UserPhone, loginInfo.Password), Encoding.UTF8, "application/x-www-form-urlencoded");
                //add important headers
                content.Headers.Add("hm-privacy-diagnostics", "false");
                content.Headers.Add("app_name", "com.xiaomi.hm.health");
                content.Headers.Add("hm-privacy-ceip", "true");
                content.Headers.Add("X-Request-Id", Guid.NewGuid().ToString());

                using var response = await httpClient.PostAsync(accessUrl, content, cancellationToken);

                if (response.StatusCode != HttpStatusCode.RedirectMethod)
                {
                    return(OperateResult.Failed(null, response.StatusCode.ToString(), "登录失败", "尝试获取AccessToken时失败"));
                }

                var parms = HttpUtility.ParseQueryString(response.Headers.Location.Query);

                var accessToken = parms["access"];

                if (string.IsNullOrWhiteSpace(accessToken))
                {
                    return(OperateResult.Failed(null, response.StatusCode.ToString(), "登录失败", "尝试获取AccessToken时失败"));
                }

                //Step two : Login to system
                string deviceId     = user?.DeviceId ?? IdentityHelper.GetRandomDeviceId();
                var    loginContent = new StringContent(XiaoMiConfig.GetLoginRequestBody(accessToken, HttpUtility.UrlEncode(deviceId, Encoding.UTF8)), Encoding.UTF8, "application/x-www-form-urlencoded");

                using var loginResponse = await httpClient.PostAsync(XiaoMiConfig.LoginUrl, loginContent, cancellationToken);

                loginResponse.EnsureSuccessStatusCode();

                var responseContent = await loginResponse.Content.ReadAsStringAsync();

                _logger.LogInformation(await loginContent.ReadAsStringAsync());
                _logger.LogInformation(responseContent);

                if (loginResponse.StatusCode != HttpStatusCode.OK)
                {
                    return(OperateResult.Failed(null, response.StatusCode.ToString(), "登录失败", responseContent));
                }

                //得到当前登录成功的用户信息
                var successModel = JsonSerializer.Deserialize <XiaoMiLoginSuccessModel>(responseContent, new JsonSerializerOptions()
                {
                    IgnoreNullValues = true
                });

                XiaoMiLoginAPISuccessModel result = new XiaoMiLoginAPISuccessModel()
                {
                    AlreadyHasUser  = user != null,
                    APIResponseData = responseContent,
                    DeviceId        = deviceId,
                    LoginToken      = successModel.token_info.login_token,
                    Token           = successModel.token_info.app_token,
                    UserId          = successModel.token_info.user_id,
                };

                return(OperateResult.Success(HttpStatusCode.OK.ToString(), "登录成功", result));
            }
            catch (Exception ex)
            {
                return(OperateResult.Failed(ex, "尝试登录时发生错误", ex.Message));
            }
        }