public async Task <IHttpActionResult> GuestLogin([FromBody] AccountLoginInfo info)
        {
            Logger.Info("Account.GuestLogin");

            var    r = new Random();
            string accountNamePostfix = r.Next(0, 1000000).ToString("D6");
            string accountName        = $"uc_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}_{accountNamePostfix}";
            string token    = EncryptHashManager.GenerateToken();
            string password = Guid.NewGuid().ToString();

            var account = new AccountEntity
            {
                AccountName     = accountName,
                IsGuest         = true,
                Password        = EncryptHashManager.ComputeHash(password),
                Token           = EncryptHashManager.GenerateToken(),
                CreatedDateTime = DateTime.UtcNow
            };

            await this.DatabaseContext.Bucket.InsertSlimAsync(account);

            var response = new AccountGuestLoginResponse
            {
                AccountId   = account.Id,
                AccountName = accountName,
                Token       = token,
                Password    = password
            };

            return(CreateSuccessResult(response));
        }
        public async Task <IHttpActionResult> Convert([FromBody] AccountConvertInfo info)
        {
            Logger.Info($"Account.Convert AccountName={info.AccountName}");

            var account = await GetAndVerifyAccount(info.AccountId);

            if (!EncryptHashManager.VerifyHash(info.OldPassword, account.Password))
            {
                await
                this.RecordLogin(account, UCenterErrorCode.AccountLoginFailedPasswordNotMatch,
                                 "The account name and password do not match");

                throw new UCenterException(UCenterErrorCode.AccountLoginFailedPasswordNotMatch);
            }

            account.AccountName   = info.AccountName;
            account.IsGuest       = false;
            account.Name          = info.Name;
            account.IdentityNum   = info.IdentityNum;
            account.Password      = EncryptHashManager.ComputeHash(info.Password);
            account.SuperPassword = EncryptHashManager.ComputeHash(info.SuperPassword);
            account.PhoneNum      = info.PhoneNum;
            account.Email         = info.Email;
            account.Sex           = info.Sex;
            await this.DatabaseContext.Bucket.UpsertSlimAsync(account);

            await this.RecordLogin(account, UCenterErrorCode.Success, "Account converted successfully.");

            return(CreateSuccessResult(ToResponse <AccountRegisterResponse>(account)));
        }
Esempio n. 3
0
        public async Task <IHttpActionResult> ResetPassword([FromBody] AccountResetPasswordInfo info, CancellationToken token)
        {
            CustomTrace.TraceInformation($"Account.ResetPassword AccountName={info.AccountName}");

            var account = await this.Database.Accounts.GetSingleAsync(a => a.AccountName == info.AccountName, token);

            if (account == null)
            {
                throw new UCenterException(UCenterErrorCode.AccountNotExist);
            }

            if (!EncryptHashManager.VerifyHash(info.SuperPassword, account.SuperPassword))
            {
                await this.RecordLogin(
                    account,
                    UCenterErrorCode.AccountLoginFailedPasswordNotMatch,
                    "The super password provided is incorrect",
                    token);

                throw new UCenterException(UCenterErrorCode.AccountLoginFailedPasswordNotMatch);
            }

            account.Password = EncryptHashManager.ComputeHash(info.Password);
            await this.Database.Accounts.UpsertAsync(account, token);

            await this.RecordLogin(account, UCenterErrorCode.Success, "Reset password successfully.", token);

            return(this.CreateSuccessResult(this.ToResponse <AccountResetPasswordResponse>(account)));
        }
Esempio n. 4
0
        public async Task <IActionResult> GuestAccess([FromBody] GuestAccessInfo info, CancellationToken token)
        {
            if (info == null)
            {
                throw new UCenterException(UCenterErrorCode.DeviceInfoNull);
            }

            if (string.IsNullOrEmpty(info.AppId))
            {
                throw new UCenterException(UCenterErrorCode.DeviceInfoNull);
            }

            EnsureDeviceInfo(info.Device);

            AccountEntity accountEntity;
            string        guestDeviceId     = $"{info.AppId}_{info.Device.Id}";
            var           guestDeviceEntity = await this.Database.GuestDevices.GetSingleAsync(guestDeviceId, token);

            if (guestDeviceEntity == null)
            {
                accountEntity = new AccountEntity()
                {
                    Id            = Guid.NewGuid().ToString(),
                    AccountName   = Guid.NewGuid().ToString(),
                    AccountType   = AccountType.Guest,
                    AccountStatus = AccountStatus.Active,
                    Token         = EncryptHashManager.GenerateToken()
                };
                await this.Database.Accounts.InsertAsync(accountEntity, token);

                guestDeviceEntity = new GuestDeviceEntity()
                {
                    Id        = $"{info.AppId}_{info.Device.Id}",
                    AccountId = accountEntity.Id,
                    AppId     = info.AppId,
                    Device    = info.Device
                };
                await this.Database.GuestDevices.InsertAsync(guestDeviceEntity, token);

                await this.TraceAccountEvent(accountEntity, "GuestRegister", info.Device, token : token);
            }
            else
            {
                accountEntity = await this.Database.Accounts.GetSingleAsync(guestDeviceEntity.AccountId, token);

                await this.TraceAccountEvent(accountEntity, "GuestLogin", info.Device, token : token);
            }

            await LogDeviceInfo(info.Device, token);

            var response = new GuestAccessResponse
            {
                AccountId   = accountEntity.Id,
                AccountName = accountEntity.AccountName,
                AccountType = accountEntity.AccountType,
                Token       = accountEntity.Token
            };

            return(this.CreateSuccessResult(response));
        }
Esempio n. 5
0
        public async Task <IHttpActionResult> GuestLogin([FromBody] AccountLoginInfo info, CancellationToken token)
        {
            CustomTrace.TraceInformation("Account.GuestLogin");

            var    r = new Random();
            string accountNamePostfix = r.Next(0, 1000000).ToString("D6");
            string accountName        = $"uc_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}_{accountNamePostfix}";
            string accountToken       = EncryptHashManager.GenerateToken();
            string password           = Guid.NewGuid().ToString();

            var account = new AccountEntity
            {
                Id          = Guid.NewGuid().ToString(),
                AccountName = accountName,
                IsGuest     = true,
                Password    = EncryptHashManager.ComputeHash(password),
                Token       = EncryptHashManager.GenerateToken()
            };

            await this.Database.Accounts.InsertAsync(account, token);

            var response = new AccountGuestLoginResponse
            {
                AccountId   = account.Id,
                AccountName = accountName,
                Token       = accountToken,
                Password    = password
            };

            return(this.CreateSuccessResult(response));
        }
Esempio n. 6
0
        public async Task <IHttpActionResult> Login([FromBody] AccountLoginInfo info, CancellationToken token)
        {
            CustomTrace.TraceInformation($"Account.Login AccountName={info.AccountName}");

            var account = await this.Database.Accounts.GetSingleAsync(a => a.AccountName == info.AccountName, token);

            if (account == null)
            {
                throw new UCenterException(UCenterErrorCode.AccountNotExist);
            }

            if (!EncryptHashManager.VerifyHash(info.Password, account.Password))
            {
                await this.RecordLogin(
                    account,
                    UCenterErrorCode.AccountLoginFailedPasswordNotMatch,
                    "The account name and password do not match",
                    token);

                throw new UCenterException(UCenterErrorCode.AccountLoginFailedPasswordNotMatch);
            }

            account.LastLoginDateTime = DateTime.UtcNow;
            account.Token             = EncryptHashManager.GenerateToken();
            await this.Database.Accounts.UpsertAsync(account, token);

            await this.RecordLogin(account, UCenterErrorCode.Success, token : token);

            return(this.CreateSuccessResult(this.ToResponse <AccountLoginResponse>(account)));
        }
        public void TestEncryptAndCompare()
        {
            string password = Guid.NewGuid().ToString();
            var    hash     = EncryptHashManager.ComputeHash(password);

            Assert.IsFalse(EncryptHashManager.VerifyHash(Guid.NewGuid().ToString(), hash));
            Assert.IsTrue(EncryptHashManager.VerifyHash(password, hash));
        }
        public void TestEncryptAndCompare()
        {
            string password = Guid.NewGuid().ToString();
            var    hash     = EncryptHashManager.ComputeHash(password);

            CustomTrace.TraceInformation("Hash code is: {0}", hash);
            Assert.IsFalse(EncryptHashManager.VerifyHash(Guid.NewGuid().ToString(), hash));
            Assert.IsTrue(EncryptHashManager.VerifyHash(password, hash));
        }
Esempio n. 9
0
        public async Task <IActionResult> WeChatLogin(AccountWeChatOAuthInfo info, CancellationToken token)
        {
            string appId     = "Todo_AppId";
            string appSecret = "Todo_AppSecret";
            string code      = "Todo_Code";
            string grantType = "authorization_code";

            string url = $"https://api.weixin.qq.com/sns/oauth2/access_token?appid={appId}&secret={appSecret}&code={code}&grant_type={grantType}";

            using (var httpClient = new HttpClient())
            {
                var response = await httpClient.GetAsync(url, token);

                var accessToken = await response.Content.ReadAsAsync <OAuthTokenResponse>(token);

                if (accessToken != null && !string.IsNullOrEmpty(accessToken.AccessToken))
                {
                    var weChatAccountEntity = await this.Database.WeChatAccounts.GetSingleAsync(a => a.OpenId == accessToken.OpenId, token);

                    if (weChatAccountEntity == null)
                    {
                        weChatAccountEntity = new WeChatAccountEntity()
                        {
                            AccountId = info.AccountId,
                            AppId     = info.AppId,
                            OpenId    = accessToken.OpenId,
                            UnionId   = accessToken.UnionId
                        };
                        await this.Database.WeChatAccounts.InsertAsync(weChatAccountEntity, token);

                        var accountEntity = new AccountEntity()
                        {
                            Id            = Guid.NewGuid().ToString(),
                            AccountName   = Guid.NewGuid().ToString(),
                            AccountType   = AccountType.Guest,
                            AccountStatus = AccountStatus.Active,
                            Token         = EncryptHashManager.GenerateToken()
                        };
                        await this.Database.Accounts.InsertAsync(accountEntity, token);

                        return(this.CreateSuccessResult(accountEntity));
                    }
                    else
                    {
                        var accountEntity = await this.Database.Accounts.GetSingleAsync(a => a.Id == weChatAccountEntity.AccountId, token);
                        await AccountLoginAsync(accountEntity, token);

                        return(this.CreateSuccessResult(accountEntity));
                    }
                }
                throw new UCenterException(UCenterErrorCode.AccountOAuthTokenUnauthorized, "OAuth Token Unauthorized");
            }
        }
Esempio n. 10
0
        public async Task <IHttpActionResult> Login([FromBody] AccountLoginInfo info)
        {
            Logger.Info($"Account.Login AccountName={info.AccountName}");

            var accountResourceByName =
                await
                this.DatabaseContext.Bucket.GetByEntityIdSlimAsync <AccountResourceEntity>(
                    AccountResourceEntity.GenerateResourceId(AccountResourceType.AccountName, info.AccountName),
                    false);

            AccountEntity account = null;

            if (accountResourceByName != null)
            {
                // this means the temp value still exists, we can directly get the account by account id.
                account =
                    await
                    this.DatabaseContext.Bucket.GetByEntityIdSlimAsync <AccountEntity>(
                        accountResourceByName.AccountId);
            }
            else
            {
                // this means the temp value not exists any more, meanwhile, it have passed a period after the account created
                // so the index should be already created and we can query the entity by query string
                account =
                    await
                    this.DatabaseContext.Bucket.FirstOrDefaultAsync <AccountEntity>(
                        a => a.AccountName == info.AccountName);
            }

            if (account == null)
            {
                throw new UCenterException(UCenterErrorCode.AccountNotExist);
            }
            if (!EncryptHashManager.VerifyHash(info.Password, account.Password))
            {
                await
                this.RecordLogin(account, UCenterErrorCode.AccountLoginFailedPasswordNotMatch,
                                 "The account name and password do not match");

                throw new UCenterException(UCenterErrorCode.AccountLoginFailedPasswordNotMatch);
            }
            account.LastLoginDateTime = DateTime.UtcNow;
            account.Token             = EncryptHashManager.GenerateToken();
            await this.DatabaseContext.Bucket.UpsertSlimAsync(account);

            await this.RecordLogin(account, UCenterErrorCode.Success);

            return(CreateSuccessResult(ToResponse <AccountLoginResponse>(account)));
        }
Esempio n. 11
0
        public async Task <IHttpActionResult> ResetPassword([FromBody] AccountResetPasswordInfo info)
        {
            Logger.Info($"Account.ResetPassword AccountName={info.AccountId}");

            var account = await GetAndVerifyAccount(info.AccountId);

            if (!EncryptHashManager.VerifyHash(info.SuperPassword, account.SuperPassword))
            {
                await
                this.RecordLogin(account, UCenterErrorCode.AccountLoginFailedPasswordNotMatch,
                                 "The super password provided is incorrect");

                throw new UCenterException(UCenterErrorCode.AccountLoginFailedPasswordNotMatch);
            }
            account.Password = EncryptHashManager.ComputeHash(info.Password);
            await this.DatabaseContext.Bucket.UpsertSlimAsync(account);

            await this.RecordLogin(account, UCenterErrorCode.Success, "Reset password successfully.");

            return(CreateSuccessResult(ToResponse <AccountResetPasswordResponse>(account)));
        }
Esempio n. 12
0
        /// <summary>
        /// Get client IP area.
        /// </summary>
        /// <param name="token">Indicating the cancellation token.</param>
        /// <returns>Async task.</returns>
        //[HttpGet]
        //[Route("api/accounts/ip")]
        //public IActionResult GetClientIp(CancellationToken token)
        //{
        //    string ipAddress = IPHelper.GetClientIpAddress(Request);
        //    return this.CreateSuccessResult(ipAddress);
        //}

        /// <summary>
        /// Generate token and login account
        /// </summary>
        /// <param name="token">Indicating the cancellation token.</param>
        /// <returns>Async task.</returns>
        private async Task AccountLoginAsync(AccountEntity accountEntity, CancellationToken token)
        {
            if (accountEntity.AccountStatus == AccountStatus.Disabled)
            {
                await this.TraceAccountErrorAsync(
                    accountEntity,
                    UCenterErrorCode.AccountDisabled,
                    "The account is disabled",
                    token);

                throw new UCenterException(UCenterErrorCode.AccountDisabled);
            }

            accountEntity.Token             = EncryptHashManager.GenerateToken();
            accountEntity.LastLoginDateTime = DateTime.UtcNow;

            var filter = Builders <AccountEntity> .Filter.Where(e => e.Id == accountEntity.Id);

            var update = Builders <AccountEntity> .Update
                         .Set("Token", accountEntity.Token)
                         .Set("LastLoginDateTime", accountEntity.LastLoginDateTime);

            await this.Database.Accounts.UpdateOneAsync <AccountEntity>(accountEntity, filter, update, token);
        }
Esempio n. 13
0
        public async Task <IHttpActionResult> Register([FromBody] AccountRegisterRequestInfo info,
                                                       CancellationToken token)
        {
            this.Logger.Info($"Account.Register AccountName={info.AccountName}");

            var removeTempsIfError = new List <AccountResourceEntity>();
            var error = false;

            try
            {
                var account =
                    await
                    DatabaseContext.Bucket.FirstOrDefaultAsync <AccountEntity>(
                        a => a.AccountName == info.AccountName, false);

                if (account != null)
                {
                    throw new UCenterException(UCenterErrorCode.AccountRegisterFailedAlreadyExist);
                }

                account = new AccountEntity
                {
                    AccountName     = info.AccountName,
                    IsGuest         = false,
                    Name            = info.Name,
                    IdentityNum     = info.IdentityNum,
                    Password        = EncryptHashManager.ComputeHash(info.Password),
                    SuperPassword   = EncryptHashManager.ComputeHash(info.SuperPassword),
                    PhoneNum        = info.PhoneNum,
                    Sex             = info.Sex,
                    CreatedDateTime = DateTime.UtcNow
                };

                if (!string.IsNullOrEmpty(account.AccountName))
                {
                    var namePointer = new AccountResourceEntity(account, AccountResourceType.AccountName);
                    await this.DatabaseContext.Bucket.InsertSlimAsync(namePointer);

                    removeTempsIfError.Add(namePointer);
                }
                if (!string.IsNullOrEmpty(account.PhoneNum))
                {
                    var phonePointer = new AccountResourceEntity(account, AccountResourceType.Phone);
                    await this.DatabaseContext.Bucket.InsertSlimAsync(phonePointer);

                    removeTempsIfError.Add(phonePointer);
                }
                else if (!string.IsNullOrEmpty(account.Email))
                {
                    var emailPointer = new AccountResourceEntity(account, AccountResourceType.Email);
                    await this.DatabaseContext.Bucket.InsertSlimAsync(emailPointer);

                    removeTempsIfError.Add(emailPointer);
                }

                // set the default profiles
                account.ProfileImage = await this.storageContext.CopyBlobAsync(
                    account.Sex == Sex.Female
                    ?this.settings.DefaultProfileImageForFemaleBlobName
                    : this.settings.DefaultProfileImageForMaleBlobName,
                    this.settings.ProfileImageForBlobNameTemplate.FormatInvariant(account.Id),
                    token);

                account.ProfileThumbnail = await this.storageContext.CopyBlobAsync(
                    account.Sex == Sex.Female
                    ?this.settings.DefaultProfileThumbnailForFemaleBlobName
                    : this.settings.DefaultProfileThumbnailForMaleBlobName,
                    this.settings.ProfileThumbnailForBlobNameTemplate.FormatInvariant(account.Id),
                    token);

                await this.DatabaseContext.Bucket.InsertSlimAsync(account);

                return(CreateSuccessResult(ToResponse <AccountRegisterResponse>(account)));
            }
            catch (Exception ex)
            {
                this.Logger.Info($"Account.Register Exception:AccoundName={info.AccountName}");
                this.Logger.Info(ex.ToString());

                error = true;
                if (ex is CouchBaseException)
                {
                    var status = (ex as CouchBaseException).Result as IDocumentResult <AccountResourceEntity>;
                    if (status != null)
                    {
                        throw new UCenterException(UCenterErrorCode.AccountRegisterFailedAlreadyExist, ex);
                    }
                }

                throw;
            }
            finally
            {
                if (error)
                {
                    foreach (var item in removeTempsIfError)
                    {
                        this.DatabaseContext.Bucket.Remove(item.ToDocument());
                    }
                }
            }
        }
Esempio n. 14
0
        public async Task <IHttpActionResult> Register([FromBody] AccountRegisterRequestInfo info, CancellationToken token)
        {
            CustomTrace.TraceInformation($"Account.Register AccountName={info.AccountName}");

            if (!ValidateAccountName(info.AccountName))
            {
                // TODO: Change to AccountRegisterFailedInvalidName in next client refresh
                throw new UCenterException(UCenterErrorCode.AccountRegisterFailedAlreadyExist);
            }

            var removeTempsIfError = new List <KeyPlaceholderEntity>();
            var error = false;

            try
            {
                var account = await this.Database.Accounts.GetSingleAsync(a => a.AccountName == info.AccountName, token);

                if (account != null)
                {
                    throw new UCenterException(UCenterErrorCode.AccountRegisterFailedAlreadyExist);
                }

                account = new AccountEntity
                {
                    Id            = Guid.NewGuid().ToString(),
                    AccountName   = info.AccountName,
                    IsGuest       = false,
                    Name          = info.Name,
                    Email         = info.Email,
                    IdentityNum   = info.IdentityNum,
                    Password      = EncryptHashManager.ComputeHash(info.Password),
                    SuperPassword = EncryptHashManager.ComputeHash(info.SuperPassword),
                    PhoneNum      = info.PhoneNum,
                    Sex           = info.Sex
                };

                var placeholders = new[]
                {
                    this.GenerateKeyPlaceholder(account.AccountName, KeyType.Name, account.Id, account.AccountName),
                    this.GenerateKeyPlaceholder(account.PhoneNum, KeyType.Phone, account.Id, account.AccountName),
                    this.GenerateKeyPlaceholder(account.Email, KeyType.Email, account.Id, account.AccountName)
                };

                foreach (var placeholder in placeholders)
                {
                    if (!string.IsNullOrEmpty(placeholder.Name))
                    {
                        await this.Database.KeyPlaceholders.InsertAsync(placeholder, token);

                        removeTempsIfError.Add(placeholder);
                    }
                }

                // set the default profiles
                account.ProfileImage = await this.storageContext.CopyBlobAsync(
                    account.Sex == Sex.Female?this.settings.DefaultProfileImageForFemaleBlobName : this.settings.DefaultProfileImageForMaleBlobName,
                    this.settings.ProfileImageForBlobNameTemplate.FormatInvariant(account.Id),
                    token);

                account.ProfileThumbnail = await this.storageContext.CopyBlobAsync(
                    account.Sex == Sex.Female
                    ?this.settings.DefaultProfileThumbnailForFemaleBlobName
                    : this.settings.DefaultProfileThumbnailForMaleBlobName,
                    this.settings.ProfileThumbnailForBlobNameTemplate.FormatInvariant(account.Id),
                    token);

                await this.Database.Accounts.InsertAsync(account, token);

                return(this.CreateSuccessResult(this.ToResponse <AccountRegisterResponse>(account)));
            }
            catch (Exception ex)
            {
                CustomTrace.TraceError(ex, "Account.Register Exception:AccoundName={info.AccountName}");

                error = true;
                if (ex is MongoWriteException)
                {
                    var mex = ex as MongoWriteException;

                    if (mex.WriteError.Category == ServerErrorCategory.DuplicateKey)
                    {
                        throw new UCenterException(UCenterErrorCode.AccountRegisterFailedAlreadyExist, ex);
                    }
                }

                throw;
            }
            finally
            {
                if (error)
                {
                    try
                    {
                        foreach (var item in removeTempsIfError)
                        {
                            this.Database.KeyPlaceholders.DeleteAsync(item, token).Wait(token);
                        }
                    }
                    catch (Exception ex)
                    {
                        CustomTrace.TraceError(ex, "Error to remove placeholder");
                    }
                }
            }
        }
        public async Task <IActionResult> WeChatLogin([FromBody] AccountWeChatOAuthInfo info, CancellationToken token)
        {
            // info.AppId目前传值不正确,应等于settings.WechatAppId
            // 后续应当根据info.AppId去查找对应WechatAppSecret
            logger.LogInformation("WeChatLogin AppId=" + info.AppId);
            logger.LogInformation("WeChatLogin AppId=" + settings.WechatAppId);
            logger.LogInformation("WeChatLogin Code=" + info.Code);

            OAuthAccessTokenResult access_token_result = null;

            try
            {
                access_token_result = await OAuthApi.GetAccessTokenAsync(
                    settings.WechatAppId, settings.WechatAppSecret, info.Code);
            }
            catch (Exception ex)
            {
                logger.LogError(ex.ToString());

                throw new UCenterException(UCenterErrorCode.AccountOAuthTokenUnauthorized);
            }

            if (access_token_result == null ||
                access_token_result.errcode != 0)
            {
                logger.LogError("GetAccessTokenAsync失败");

                throw new UCenterException(UCenterErrorCode.AccountOAuthTokenUnauthorized);
            }

            OAuthUserInfo user_info = null;

            try
            {
                user_info = await OAuthApi.GetUserInfoAsync(
                    access_token_result.access_token, access_token_result.openid);
            }
            catch (Exception ex)
            {
                logger.LogError(ex.ToString());

                throw new UCenterException(UCenterErrorCode.AccountOAuthTokenUnauthorized);
            }

            if (user_info == null)
            {
                logger.LogError("OAuthUserInfo为空");

                throw new UCenterException(UCenterErrorCode.AccountOAuthTokenUnauthorized);
            }

            logger.LogInformation("OpenId=" + user_info.openid);
            logger.LogInformation("NickName=" + user_info.nickname);
            logger.LogInformation("Sex=" + user_info.sex);
            logger.LogInformation("Province=" + user_info.province);
            logger.LogInformation("City=" + user_info.city);
            logger.LogInformation("Country=" + user_info.country);
            logger.LogInformation("Headimgurl=" + user_info.headimgurl);
            logger.LogInformation("Unionid=" + user_info.unionid);
            if (user_info.privilege != null)
            {
                foreach (var i in user_info.privilege)
                {
                    if (i != null)
                    {
                        logger.LogInformation("Privilege=" + i);
                    }
                }
            }

            bool need_update_nickname = false;
            bool need_update_icon     = false;

            // 查找AccountWechat
            var acc_wechat = await this.Database.AccountWechat.GetSingleAsync(
                a => a.Unionid == user_info.unionid &&
                a.OpenId == user_info.openid &&
                a.AppId == settings.WechatAppId,
                token);

            // 创建AccountWechat
            if (acc_wechat == null)
            {
                acc_wechat = new AccountWechatEntity()
                {
                    Id         = Guid.NewGuid().ToString(),
                    AccountId  = Guid.NewGuid().ToString(),
                    Unionid    = user_info.unionid,
                    OpenId     = user_info.openid,
                    AppId      = settings.WechatAppId,
                    NickName   = user_info.nickname,
                    Gender     = (Gender)user_info.sex,
                    Province   = user_info.province,
                    City       = user_info.city,
                    Country    = user_info.country,
                    Headimgurl = user_info.headimgurl
                };

                await this.Database.AccountWechat.InsertAsync(acc_wechat, token);

                need_update_nickname = true;
                need_update_icon     = true;
            }
            else
            {
                if (acc_wechat.Headimgurl != user_info.headimgurl)
                {
                    acc_wechat.Headimgurl = user_info.headimgurl;
                    need_update_icon      = true;
                }

                if (acc_wechat.NickName != user_info.nickname)
                {
                    acc_wechat.NickName  = user_info.nickname;
                    need_update_nickname = true;
                }

                if (need_update_icon || need_update_nickname)
                {
                    await this.Database.AccountWechat.UpsertAsync(acc_wechat, token);
                }
            }

            // 查找Account
            var acc = await this.Database.Accounts.GetSingleAsync(
                acc_wechat.AccountId, token);

            // 创建Account
            if (acc == null)
            {
                acc = new AccountEntity()
                {
                    Id            = acc_wechat.AccountId,
                    AccountName   = Guid.NewGuid().ToString(),
                    AccountType   = AccountType.NormalAccount,
                    AccountStatus = AccountStatus.Active,
                    //Password = EncryptHelper.ComputeHash(info.Password),
                    //SuperPassword = EncryptHelper.ComputeHash(info.SuperPassword),
                    Token    = EncryptHashManager.GenerateToken(),
                    Gender   = acc_wechat.Gender,
                    Identity = string.Empty,
                    Phone    = string.Empty,
                    Email    = string.Empty
                };

                await this.Database.Accounts.InsertAsync(acc, token);

                need_update_nickname = true;
                need_update_icon     = true;
            }

            // 微信头像覆盖Acc头像
            if (need_update_icon &&
                !string.IsNullOrEmpty(user_info.headimgurl))
            {
                //logger.LogInformation("微信头像覆盖Acc头像,Headimgurl={0}", acc_wechat.Headimgurl);

                await DownloadWechatHeadIcon(user_info.headimgurl, acc.Id, token);

                acc.ProfileImage = user_info.headimgurl;
                await this.Database.Accounts.UpsertAsync(acc, token);
            }

            string current_nickname = string.Empty;
            var    app          = UCenterContext.Instance.CacheAppEntity.GetAppEntityByWechatAppId(settings.WechatAppId);
            var    data_id      = $"{app.Id}_{acc.Id}";
            var    account_data = await this.Database.AppAccountDatas.GetSingleAsync(data_id, token);

            if (account_data != null)
            {
                var m = JsonConvert.DeserializeObject <Dictionary <string, string> >(account_data.Data);
                if (m.ContainsKey("nick_name"))
                {
                    current_nickname = m["nick_name"];
                }

                // 微信昵称覆盖Acc昵称
                if (current_nickname != acc_wechat.NickName && !string.IsNullOrEmpty(acc_wechat.NickName))
                {
                    m["nick_name"]    = acc_wechat.NickName;
                    account_data.Data = JsonConvert.SerializeObject(m);

                    await this.Database.AppAccountDatas.UpsertAsync(account_data, token);
                }
            }
            else
            {
                Dictionary <string, string> m = new Dictionary <string, string>();
                m["nick_name"] = acc_wechat.NickName;

                account_data = new AppAccountDataEntity
                {
                    Id        = data_id,
                    AppId     = app.Id,
                    AccountId = acc.Id,
                    Data      = JsonConvert.SerializeObject(m)
                };

                await this.Database.AppAccountDatas.UpsertAsync(account_data, token);
            }

            return(this.CreateSuccessResult(this.ToResponse <AccountLoginResponse>(acc)));
        }