using LeanCloud.Storage.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; namespace LeanCloud { /// /// Represents a user for a LeanCloud application. /// [AVClassName("_User")] public class AVUser : AVObject { private static readonly IDictionary authProviders = new Dictionary(); private static readonly HashSet readOnlyKeys = new HashSet { "sessionToken", "isNew" }; internal static IAVUserController UserController { get { return AVPlugins.Instance.UserController; } } internal static IAVCurrentUserController CurrentUserController { get { return AVPlugins.Instance.CurrentUserController; } } /// /// Whether the AVUser has been authenticated on this device. Only an authenticated /// AVUser can be saved and deleted. /// [Obsolete("This property is deprecated, please use IsAuthenticatedAsync instead.")] public bool IsAuthenticated { get { lock (mutex) { return SessionToken != null && CurrentUser != null && CurrentUser.ObjectId == ObjectId; } } } /// /// Whether the AVUser has been authenticated on this device, and the AVUser's session token is expired. /// Only an authenticated AVUser can be saved and deleted. /// public Task IsAuthenticatedAsync() { lock (mutex) { if (SessionToken == null || CurrentUser == null || CurrentUser.ObjectId != ObjectId) { return Task.FromResult(false); } } var command = new AVCommand(String.Format("users/me?session_token={0}", CurrentSessionToken), method: "GET", data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// Refresh this user's session token, and current session token will be invalid. /// public Task RefreshSessionTokenAsync(CancellationToken cancellationToken) { return UserController.RefreshSessionTokenAsync(ObjectId, SessionToken, cancellationToken).OnSuccess(t => { var serverState = t.Result; HandleSave(serverState); }); } /// /// Removes a key from the object's data if it exists. /// /// The key to remove. /// Cannot remove the username key. public override void Remove(string key) { if (key == "username") { throw new ArgumentException("Cannot remove the username key."); } base.Remove(key); } protected override bool IsKeyMutable(string key) { return !readOnlyKeys.Contains(key); } internal override void HandleSave(IObjectState serverState) { base.HandleSave(serverState); SynchronizeAllAuthData(); CleanupAuthData(); MutateState(mutableClone => { mutableClone.ServerData.Remove("password"); }); } /// /// authenticated token. /// public string SessionToken { get { if (State.ContainsKey("sessionToken")) { return State["sessionToken"] as string; } return null; } } internal static string CurrentSessionToken { get { Task sessionTokenTask = GetCurrentSessionTokenAsync(); sessionTokenTask.Wait(); return sessionTokenTask.Result; } } internal static Task GetCurrentSessionTokenAsync(CancellationToken cancellationToken = default) { return CurrentUserController.GetCurrentSessionTokenAsync(cancellationToken); } internal Task SetSessionTokenAsync(string newSessionToken) { return SetSessionTokenAsync(newSessionToken, CancellationToken.None); } internal Task SetSessionTokenAsync(string newSessionToken, CancellationToken cancellationToken) { MutateState(mutableClone => { mutableClone.ServerData["sessionToken"] = newSessionToken; }); return SaveCurrentUserAsync(this); } /// /// Gets or sets the username. /// [AVFieldName("username")] public string Username { get { return GetProperty(null, "Username"); } set { SetProperty(value, "Username"); } } /// /// Sets the password. /// [AVFieldName("password")] public string Password { private get { return GetProperty(null, "Password"); } set { SetProperty(value, "Password"); } } /// /// Sets the email address. /// [AVFieldName("email")] public string Email { get { return GetProperty(null, "Email"); } set { SetProperty(value, "Email"); } } /// /// 用户手机号。 /// [AVFieldName("mobilePhoneNumber")] public string MobilePhoneNumber { get { return GetProperty(null, "MobilePhoneNumber"); } set { SetProperty(value, "MobilePhoneNumber"); } } /// /// 用户手机号是否已经验证 /// /// true if mobile phone verified; otherwise, false. [AVFieldName("mobilePhoneVerified")] public bool MobilePhoneVerified { get { return GetProperty(false, "MobilePhoneVerified"); } set { SetProperty(value, "MobilePhoneVerified"); } } /// /// 判断用户是否为匿名用户 /// public bool IsAnonymous { get { bool rtn = false; if (this.AuthData != null) { rtn = this.AuthData.Keys.Contains("anonymous"); } return rtn; } } internal Task SignUpAsync(Task toAwait, CancellationToken cancellationToken) { return this.Create(toAwait, cancellationToken).OnSuccess(_ => SaveCurrentUserAsync(this)).Unwrap(); } /// /// Signs up a new user. This will create a new AVUser on the server and will also persist the /// session on disk so that you can access the user using . A username and /// password must be set before calling SignUpAsync. /// public Task SignUpAsync() { return SignUpAsync(CancellationToken.None); } /// /// Signs up a new user. This will create a new AVUser on the server and will also persist the /// session on disk so that you can access the user using . A username and /// password must be set before calling SignUpAsync. /// /// The cancellation token. public Task SignUpAsync(CancellationToken cancellationToken) { return taskQueue.Enqueue(toAwait => SignUpAsync(toAwait, cancellationToken), cancellationToken); } #region 事件流系统相关 API /// /// 关注某个用户 /// /// 被关注的用户 /// public Task FollowAsync(string userObjectId) { return this.FollowAsync(userObjectId, null); } /// /// 关注某个用户 /// /// 被关注的用户Id /// 关注的时候附加属性 /// public Task FollowAsync(string userObjectId, IDictionary data) { if (data != null) { data = this.EncodeForSaving(data); } var command = new AVCommand(string.Format("users/{0}/friendship/{1}", this.ObjectId, userObjectId), method: "POST", sessionToken: CurrentSessionToken, data: data); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 取关某一个用户 /// /// /// public Task UnfollowAsync(string userObjectId) { var command = new AVCommand(string.Format("users/{0}/friendship/{1}", this.ObjectId, userObjectId), method: "DELETE", sessionToken: CurrentSessionToken, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 获取当前用户的关注者的查询 /// /// public AVQuery GetFollowerQuery() { AVQuery query = new AVQuery(); query.RelativeUri = string.Format("users/{0}/followers", this.ObjectId); return query; } /// /// 获取当前用户所关注的用户的查询 /// /// public AVQuery GetFolloweeQuery() { AVQuery query = new AVQuery(); query.RelativeUri = string.Format("users/{0}/followees", this.ObjectId); return query; } /// /// 同时查询关注了当前用户的关注者和当前用户所关注的用户 /// /// public AVQuery GetFollowersAndFolloweesQuery() { AVQuery query = new AVQuery(); query.RelativeUri = string.Format("users/{0}/followersAndFollowees", this.ObjectId); return query; } /// /// 获取当前用户的关注者 /// /// public Task> GetFollowersAsync() { return this.GetFollowerQuery().FindAsync(); } /// /// 获取当前用户所关注的用户 /// /// public Task> GetFolloweesAsync() { return this.GetFolloweeQuery().FindAsync(); } //public Task SendStatusAsync() //{ //} #endregion /// /// Logs in a user with a username and password. On success, this saves the session to disk so you /// can retrieve the currently logged in user using . /// /// The username to log in with. /// The password to log in with. /// The newly logged-in user. public static Task LogInAsync(string username, string password) { return LogInAsync(username, password, CancellationToken.None); } /// /// Logs in a user with a username and password. On success, this saves the session to disk so you /// can retrieve the currently logged in user using . /// /// The username to log in with. /// The password to log in with. /// The cancellation token. /// The newly logged-in user. public static Task LogInAsync(string username, string password, CancellationToken cancellationToken) { return UserController.LogInAsync(username, null, password, cancellationToken).OnSuccess(t => { AVUser user = AVObject.FromState(t.Result, "_User"); return SaveCurrentUserAsync(user).OnSuccess(_ => user); }).Unwrap(); } /// /// Logs in a user with a username and password. On success, this saves the session to disk so you /// can retrieve the currently logged in user using . /// /// The session token to authorize with /// The user if authorization was successful public static Task BecomeAsync(string sessionToken) { return BecomeAsync(sessionToken, CancellationToken.None); } /// /// Logs in a user with a username and password. On success, this saves the session to disk so you /// can retrieve the currently logged in user using . /// /// The session token to authorize with /// The cancellation token. /// The user if authorization was successful public static Task BecomeAsync(string sessionToken, CancellationToken cancellationToken) { return UserController.GetUserAsync(sessionToken, cancellationToken).OnSuccess(t => { AVUser user = AVObject.FromState(t.Result, "_User"); return SaveCurrentUserAsync(user).OnSuccess(_ => user); }).Unwrap(); } protected override Task SaveAsync(Task toAwait, CancellationToken cancellationToken) { lock (mutex) { if (ObjectId == null) { throw new InvalidOperationException("You must call SignUpAsync before calling SaveAsync."); } return base.SaveAsync(toAwait, cancellationToken).OnSuccess(_ => { if (!CurrentUserController.IsCurrent(this)) { return Task.FromResult(0); } return SaveCurrentUserAsync(this); }).Unwrap(); } } internal override Task FetchAsyncInternal(Task toAwait, IDictionary queryString, CancellationToken cancellationToken) { return base.FetchAsyncInternal(toAwait, queryString, cancellationToken).OnSuccess(t => { if (!CurrentUserController.IsCurrent(this)) { return Task.FromResult(t.Result); } // If this is already the current user, refresh its state on disk. return SaveCurrentUserAsync(this).OnSuccess(_ => t.Result); }).Unwrap(); } /// /// Logs out the currently logged in user session. This will remove the session from disk, log out of /// linked services, and future calls to will return null. /// /// /// Typically, you should use , unless you are managing your own threading. /// public static void LogOut() { // TODO (hallucinogen): this will without a doubt fail in Unity. But what else can we do? LogOutAsync().Wait(); } /// /// Logs out the currently logged in user session. This will remove the session from disk, log out of /// linked services, and future calls to will return null. /// /// /// This is preferable to using , unless your code is already running from a /// background thread. /// public static Task LogOutAsync() { return LogOutAsync(CancellationToken.None); } /// /// Logs out the currently logged in user session. This will remove the session from disk, log out of /// linked services, and future calls to will return null. /// /// This is preferable to using , unless your code is already running from a /// background thread. /// public static Task LogOutAsync(CancellationToken cancellationToken) { return GetCurrentUserAsync().OnSuccess(t => { LogOutWithProviders(); AVUser user = t.Result; if (user == null) { return Task.FromResult(0); } return user.taskQueue.Enqueue(toAwait => user.LogOutAsync(toAwait, cancellationToken), cancellationToken); }).Unwrap(); } internal Task LogOutAsync(Task toAwait, CancellationToken cancellationToken) { string oldSessionToken = SessionToken; if (oldSessionToken == null) { return Task.FromResult(0); } // Cleanup in-memory session. MutateState(mutableClone => { mutableClone.ServerData.Remove("sessionToken"); }); var revokeSessionTask = AVSession.RevokeAsync(oldSessionToken, cancellationToken); return Task.WhenAll(revokeSessionTask, CurrentUserController.LogOutAsync(cancellationToken)); } private static void LogOutWithProviders() { foreach (var provider in authProviders.Values) { provider.Deauthenticate(); } } /// /// Gets the currently logged in AVUser with a valid session, either from memory or disk /// if necessary. /// public static AVUser CurrentUser { get { var userTask = GetCurrentUserAsync(); // TODO (hallucinogen): this will without a doubt fail in Unity. How should we fix it? userTask.Wait(); return userTask.Result; } } public static Task GetCurrentAsync() { var userTask = GetCurrentUserAsync(); return userTask; } /// /// Gets the currently logged in AVUser with a valid session, either from memory or disk /// if necessary, asynchronously. /// public static Task GetCurrentUserAsync() { return GetCurrentUserAsync(CancellationToken.None); } /// /// Gets the currently logged in AVUser with a valid session, either from memory or disk /// if necessary, asynchronously. /// internal static Task GetCurrentUserAsync(CancellationToken cancellationToken) { return CurrentUserController.GetAsync(cancellationToken); } private static Task SaveCurrentUserAsync(AVUser user) { return SaveCurrentUserAsync(user, CancellationToken.None); } private static Task SaveCurrentUserAsync(AVUser user, CancellationToken cancellationToken) { return CurrentUserController.SetAsync(user, cancellationToken); } internal static void ClearInMemoryUser() { CurrentUserController.ClearFromMemory(); } /// /// Constructs a for AVUsers. /// public static AVQuery Query { get { return new AVQuery(); } } #region Legacy / Revocable Session Tokens private static readonly object isRevocableSessionEnabledMutex = new object(); private static bool isRevocableSessionEnabled; /// /// Tells server to use revocable session on LogIn and SignUp, even when App's Settings /// has "Require Revocable Session" turned off. Issues network request in background to /// migrate the sessionToken on disk to revocable session. /// /// The Task that upgrades the session. public static Task EnableRevocableSessionAsync() { return EnableRevocableSessionAsync(CancellationToken.None); } /// /// Tells server to use revocable session on LogIn and SignUp, even when App's Settings /// has "Require Revocable Session" turned off. Issues network request in background to /// migrate the sessionToken on disk to revocable session. /// /// The Task that upgrades the session. public static Task EnableRevocableSessionAsync(CancellationToken cancellationToken) { lock (isRevocableSessionEnabledMutex) { isRevocableSessionEnabled = true; } return GetCurrentUserAsync(cancellationToken).OnSuccess(t => { var user = t.Result; return user.UpgradeToRevocableSessionAsync(cancellationToken); }); } internal static void DisableRevocableSession() { lock (isRevocableSessionEnabledMutex) { isRevocableSessionEnabled = false; } } internal static bool IsRevocableSessionEnabled { get { lock (isRevocableSessionEnabledMutex) { return isRevocableSessionEnabled; } } } internal Task UpgradeToRevocableSessionAsync() { return UpgradeToRevocableSessionAsync(CancellationToken.None); } public Task UpgradeToRevocableSessionAsync(CancellationToken cancellationToken) { return taskQueue.Enqueue(toAwait => UpgradeToRevocableSessionAsync(toAwait, cancellationToken), cancellationToken); } internal Task UpgradeToRevocableSessionAsync(Task toAwait, CancellationToken cancellationToken) { string sessionToken = SessionToken; return toAwait.OnSuccess(_ => { return AVSession.UpgradeToRevocableSessionAsync(sessionToken, cancellationToken); }).Unwrap().OnSuccess(t => { return SetSessionTokenAsync(t.Result); }).Unwrap(); } #endregion /// /// Requests a password reset email to be sent to the specified email address associated with the /// user account. This email allows the user to securely reset their password on the LeanCloud site. /// /// The email address associated with the user that forgot their password. public static Task RequestPasswordResetAsync(string email) { return RequestPasswordResetAsync(email, CancellationToken.None); } /// /// Requests a password reset email to be sent to the specified email address associated with the /// user account. This email allows the user to securely reset their password on the LeanCloud site. /// /// The email address associated with the user that forgot their password. /// The cancellation token. public static Task RequestPasswordResetAsync(string email, CancellationToken cancellationToken) { return UserController.RequestPasswordResetAsync(email, cancellationToken); } /// /// Updates current user's password. Need the user's old password, /// /// The password. /// Old password. /// New password. /// Cancellation token. public Task UpdatePassword(string oldPassword, string newPassword, CancellationToken cancellationToken) { return UserController.UpdatePasswordAsync(ObjectId, SessionToken, oldPassword, newPassword, cancellationToken); } /// /// Gets the authData for this user. /// internal IDictionary> AuthData { get { IDictionary> authData; if (this.TryGetValue>>( "authData", out authData)) { return authData; } return null; } private set { this["authData"] = value; } } private static IAVAuthenticationProvider GetProvider(string providerName) { IAVAuthenticationProvider provider; if (authProviders.TryGetValue(providerName, out provider)) { return provider; } return null; } /// /// Removes null values from authData (which exist temporarily for unlinking) /// private void CleanupAuthData() { lock (mutex) { if (!CurrentUserController.IsCurrent(this)) { return; } var authData = AuthData; if (authData == null) { return; } foreach (var pair in new Dictionary>(authData)) { if (pair.Value == null) { authData.Remove(pair.Key); } } } } /// /// Synchronizes authData for all providers. /// private void SynchronizeAllAuthData() { lock (mutex) { var authData = AuthData; if (authData == null) { return; } foreach (var pair in authData) { SynchronizeAuthData(GetProvider(pair.Key)); } } } private void SynchronizeAuthData(IAVAuthenticationProvider provider) { bool restorationSuccess = false; lock (mutex) { var authData = AuthData; if (authData == null || provider == null) { return; } IDictionary data; if (authData.TryGetValue(provider.AuthType, out data)) { restorationSuccess = provider.RestoreAuthentication(data); } } if (!restorationSuccess) { this.UnlinkFromAsync(provider.AuthType, CancellationToken.None); } } public Task LinkWithAsync(string authType, IDictionary data, CancellationToken cancellationToken) { return taskQueue.Enqueue(toAwait => { AuthData = new Dictionary>(); AuthData[authType] = data; return SaveAsync(cancellationToken); }, cancellationToken); } public Task LinkWithAsync(string authType, CancellationToken cancellationToken) { var provider = GetProvider(authType); return provider.AuthenticateAsync(cancellationToken) .OnSuccess(t => LinkWithAsync(authType, t.Result, cancellationToken)) .Unwrap(); } /// /// Unlinks a user from a service. /// public Task UnlinkFromAsync(string authType, CancellationToken cancellationToken) { return LinkWithAsync(authType, null, cancellationToken); } /// /// Checks whether a user is linked to a service. /// internal bool IsLinked(string authType) { lock (mutex) { return AuthData != null && AuthData.ContainsKey(authType) && AuthData[authType] != null; } } internal static Task LogInWithAsync(string authType, IDictionary data, bool failOnNotExist, CancellationToken cancellationToken) { AVUser user = null; return UserController.LogInAsync(authType, data, failOnNotExist, cancellationToken).OnSuccess(t => { user = AVObject.FromState(t.Result, "_User"); lock (user.mutex) { if (user.AuthData == null) { user.AuthData = new Dictionary>(); } user.AuthData[authType] = data; user.SynchronizeAllAuthData(); } return SaveCurrentUserAsync(user); }).Unwrap().OnSuccess(t => user); } internal static Task LogInWithAsync(string authType, CancellationToken cancellationToken) { var provider = GetProvider(authType); return provider.AuthenticateAsync(cancellationToken) .OnSuccess(authData => LogInWithAsync(authType, authData.Result, false, cancellationToken)) .Unwrap(); } internal static void RegisterProvider(IAVAuthenticationProvider provider) { authProviders[provider.AuthType] = provider; var curUser = AVUser.CurrentUser; if (curUser != null) { curUser.SynchronizeAuthData(provider); } } #region 手机号登录 internal static Task LogInWithParametersAsync(Dictionary strs, CancellationToken cancellationToken) { AVUser avUser = AVObject.CreateWithoutData(null); return UserController.LogInWithParametersAsync("login", strs, cancellationToken).OnSuccess(t => { var user = (AVUser)AVObject.CreateWithoutData(null); user.HandleFetchResult(t.Result); return SaveCurrentUserAsync(user).OnSuccess(_ => user); }).Unwrap(); } /// /// 以手机号和密码实现登陆。 /// /// 手机号 /// 密码 /// public static Task LogInByMobilePhoneNumberAsync(string mobilePhoneNumber, string password) { return AVUser.LogInByMobilePhoneNumberAsync(mobilePhoneNumber, password, CancellationToken.None); } /// /// 用邮箱作和密码匹配登录 /// /// 邮箱 /// 密码 /// public static Task LogInByEmailAsync(string email, string password, CancellationToken cancellationToken = default) { return UserController.LogInAsync(null, email, password, cancellationToken).OnSuccess(t => { AVUser user = AVObject.FromState(t.Result, "_User"); return SaveCurrentUserAsync(user).OnSuccess(_ => user); }).Unwrap(); } /// /// 以手机号和密码匹配登陆 /// /// 手机号 /// 密码 /// /// public static Task LogInByMobilePhoneNumberAsync(string mobilePhoneNumber, string password, CancellationToken cancellationToken) { Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, { "password", password } }; return AVUser.LogInWithParametersAsync(strs, cancellationToken); } /// /// 以手机号和验证码登陆 /// /// 手机号 /// 短信验证码 /// /// public static Task LogInBySmsCodeAsync(string mobilePhoneNumber, string smsCode, CancellationToken cancellationToken = default) { Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, { "smsCode", smsCode } }; return AVUser.LogInWithParametersAsync(strs, cancellationToken); } /// /// Requests the login SMS code asynchronous. /// /// The mobile phone number. /// public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber) { return AVUser.RequestLogInSmsCodeAsync(mobilePhoneNumber, CancellationToken.None); } /// /// Requests the login SMS code asynchronous. /// /// The mobile phone number. /// Validate token. /// public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, string validateToken) { return AVUser.RequestLogInSmsCodeAsync(mobilePhoneNumber, null, CancellationToken.None); } /// /// Requests the login SMS code asynchronous. /// /// The mobile phone number. /// The cancellation token. /// public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, CancellationToken cancellationToken) { return RequestLogInSmsCodeAsync(mobilePhoneNumber, null, cancellationToken); } /// /// Requests the login SMS code asynchronous. /// /// The mobile phone number. /// Validate token. /// The cancellation token. /// public static Task RequestLogInSmsCodeAsync(string mobilePhoneNumber, string validateToken, CancellationToken cancellationToken) { Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, }; if (String.IsNullOrEmpty(validateToken)) { strs.Add("validate_token", validateToken); } var command = new AVCommand("requestLoginSmsCode", method: "POST", sessionToken: CurrentSessionToken, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 手机号一键登录 /// /// 手机号 /// 短信验证码 /// public static Task SignUpOrLogInByMobilePhoneAsync(string mobilePhoneNumber, string smsCode, CancellationToken cancellationToken) { Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, { "smsCode", smsCode } }; return UserController.LogInWithParametersAsync("usersByMobilePhone", strs, cancellationToken).OnSuccess(t => { var user = (AVUser)AVObject.CreateWithoutData(null); user.HandleFetchResult(t.Result); return SaveCurrentUserAsync(user).OnSuccess(_ => user); }).Unwrap(); } /// /// 手机号一键登录 /// /// signup or login by mobile phone async. /// 手机号 /// 短信验证码 public static Task SignUpOrLogInByMobilePhoneAsync(string mobilePhoneNumber, string smsCode) { return AVUser.SignUpOrLogInByMobilePhoneAsync(mobilePhoneNumber, smsCode, CancellationToken.None); } #region mobile sms shortcode sign up & log in. /// /// Send sign up sms code async. /// /// The sign up sms code async. /// Mobile phone number. public static Task SendSignUpSmsCodeAsync(string mobilePhoneNumber) { return AVCloud.RequestSMSCodeAsync(mobilePhoneNumber); } /// /// Sign up by mobile phone async. /// /// The up by mobile phone async. /// Mobile phone number. /// Sms code. public static Task SignUpByMobilePhoneAsync(string mobilePhoneNumber, string smsCode) { return AVUser.SignUpOrLogInByMobilePhoneAsync(mobilePhoneNumber, smsCode); } /// /// Send log in sms code async. /// /// The log in sms code async. /// Mobile phone number. public static Task SendLogInSmsCodeAsync(string mobilePhoneNumber) { return AVUser.RequestLogInSmsCodeAsync(mobilePhoneNumber); } /// /// Log in by mobile phone async. /// /// The in by mobile phone async. /// Mobile phone number. /// Sms code. public static Task LogInByMobilePhoneAsync(string mobilePhoneNumber, string smsCode) { return LogInBySmsCodeAsync(mobilePhoneNumber, smsCode); } #endregion #endregion #region 重置密码 /// /// 请求重置密码,需要传入注册时使用的手机号。 /// /// 注册时使用的手机号 /// public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber) { return AVUser.RequestPasswordResetBySmsCode(mobilePhoneNumber, null, CancellationToken.None); } /// /// 请求重置密码,需要传入注册时使用的手机号。 /// /// 注册时使用的手机号 /// cancellationToken /// public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, CancellationToken cancellationToken) { return RequestPasswordResetBySmsCode(mobilePhoneNumber, null, cancellationToken); } /// /// 请求重置密码,需要传入注册时使用的手机号。 /// /// 注册时使用的手机号 /// Validate token. /// public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, string validateToken) { return AVUser.RequestPasswordResetBySmsCode(mobilePhoneNumber, validateToken, CancellationToken.None); } /// /// 请求重置密码,需要传入注册时使用的手机号。 /// /// 注册时使用的手机号 /// Validate token. /// cancellationToken /// public static Task RequestPasswordResetBySmsCode(string mobilePhoneNumber, string validateToken, CancellationToken cancellationToken) { string currentSessionToken = AVUser.CurrentSessionToken; Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, }; if (String.IsNullOrEmpty(validateToken)) { strs.Add("validate_token", validateToken); } var command = new AVCommand("requestPasswordResetBySmsCode", method: "POST", sessionToken: currentSessionToken, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 通过验证码重置密码。 /// /// 新密码 /// 6位数验证码 /// public static Task ResetPasswordBySmsCodeAsync(string newPassword, string smsCode) { return AVUser.ResetPasswordBySmsCodeAsync(newPassword, smsCode, CancellationToken.None); } /// /// 通过验证码重置密码。 /// /// 新密码 /// 6位数验证码 /// cancellationToken /// public static Task ResetPasswordBySmsCodeAsync(string newPassword, string smsCode, CancellationToken cancellationToken) { string currentSessionToken = AVUser.CurrentSessionToken; Dictionary strs = new Dictionary() { { "password", newPassword } }; var command = new AVCommand("resetPasswordBySmsCode/" + smsCode, method: "PUT", sessionToken: currentSessionToken, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 发送认证码到需要认证的手机上 /// /// 手机号 /// public static Task RequestMobilePhoneVerifyAsync(string mobilePhoneNumber) { return AVUser.RequestMobilePhoneVerifyAsync(mobilePhoneNumber, null, CancellationToken.None); } /// /// 发送认证码到需要认证的手机上 /// /// 手机号 /// Validate token. /// public static Task RequestMobilePhoneVerifyAsync(string mobilePhoneNumber, string validateToken) { return AVUser.RequestMobilePhoneVerifyAsync(mobilePhoneNumber, validateToken, CancellationToken.None); } /// /// 发送认证码到需要认证的手机上 /// /// 手机号 /// CancellationToken /// public static Task RequestMobilePhoneVerifyAsync(string mobilePhoneNumber, CancellationToken cancellationToken) { return RequestMobilePhoneVerifyAsync(mobilePhoneNumber, null, cancellationToken); } /// /// 发送认证码到需要认证的手机上 /// /// 手机号 /// Validate token. /// CancellationToken /// public static Task RequestMobilePhoneVerifyAsync(string mobilePhoneNumber, string validateToken, CancellationToken cancellationToken) { string currentSessionToken = AVUser.CurrentSessionToken; Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber } }; if (String.IsNullOrEmpty(validateToken)) { strs.Add("validate_token", validateToken); } var command = new AVCommand("requestMobilePhoneVerify", method: "POST", sessionToken: currentSessionToken, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 验证手机验证码是否为有效值 /// /// 手机收到的验证码 /// 手机号 /// public static Task VerifyMobilePhoneAsync(string code, string mobilePhoneNumber) { return AVUser.VerifyMobilePhoneAsync(code, mobilePhoneNumber, CancellationToken.None); } /// /// 验证手机验证码是否为有效值 /// /// 手机收到的验证码 /// 手机号,可选 /// /// public static Task VerifyMobilePhoneAsync(string code, string mobilePhoneNumber, CancellationToken cancellationToken) { var command = new AVCommand("verifyMobilePhone/" + code.Trim() + "?mobilePhoneNumber=" + mobilePhoneNumber.Trim(), method: "POST", sessionToken: null, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 验证手机验证码是否为有效值 /// /// 手机收到的验证码 /// public static Task VerifyMobilePhoneAsync(string code) { var command = new AVCommand("verifyMobilePhone/" + code.Trim(), method: "POST", sessionToken: null, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 验证手机验证码是否为有效值 /// /// 手机收到的验证码 /// cancellationToken /// public static Task VerifyMobilePhoneAsync(string code, CancellationToken cancellationToken) { return AVUser.VerifyMobilePhoneAsync(code, CancellationToken.None); } #endregion #region 邮箱验证 /// /// 申请发送验证邮箱的邮件,一周之内有效 /// 如果该邮箱已经验证通过,会直接返回 True,并不会真正发送邮件 /// 注意,不能频繁的调用此接口,一天之内只允许向同一个邮箱发送验证邮件 3 次,超过调用次数,会直接返回错误 /// /// 邮箱地址 /// public static Task RequestEmailVerifyAsync(string email) { Dictionary strs = new Dictionary() { { "email", email } }; var command = new AVCommand("requestEmailVerify", method: "POST", sessionToken: null, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } #endregion #region in no-local-storage enviroment internal Task Create() { return this.Create(CancellationToken.None); } internal Task Create(CancellationToken cancellationToken) { return taskQueue.Enqueue(toAwait => Create(toAwait, cancellationToken), cancellationToken); } internal Task Create(Task toAwait, CancellationToken cancellationToken) { if (AuthData == null) { // TODO (hallucinogen): make an Extension of Task to create Task with exception/canceled. if (string.IsNullOrEmpty(Username)) { TaskCompletionSource tcs = new TaskCompletionSource(); tcs.TrySetException(new InvalidOperationException("Cannot sign up user with an empty name.")); return tcs.Task; } if (string.IsNullOrEmpty(Password)) { TaskCompletionSource tcs = new TaskCompletionSource(); tcs.TrySetException(new InvalidOperationException("Cannot sign up user with an empty password.")); return tcs.Task; } } if (!string.IsNullOrEmpty(ObjectId)) { TaskCompletionSource tcs = new TaskCompletionSource(); tcs.TrySetException(new InvalidOperationException("Cannot sign up a user that already exists.")); return tcs.Task; } IDictionary currentOperations = StartSave(); return toAwait.OnSuccess(_ => { return UserController.SignUpAsync(State, currentOperations, cancellationToken); }).Unwrap().ContinueWith(t => { if (t.IsFaulted || t.IsCanceled) { HandleFailedSave(currentOperations); } else { var serverState = t.Result; HandleSave(serverState); } return t; }).Unwrap(); } #endregion #region task session token for http request internal static Task TakeSessionToken(string sesstionToken = null) { var sessionTokenTask = Task.FromResult(sesstionToken); if (sesstionToken == null) sessionTokenTask = AVUser.GetCurrentAsync().OnSuccess(u => { if (u.Result != null) return u.Result.SessionToken; return null; }); return sessionTokenTask; } #endregion #region AVUser Extension public IDictionary> GetAuthData() { return AuthData; } /// /// use 3rd auth data to sign up or log in.if user with the same auth data exits,it will transfer as log in. /// /// OAuth data, like {"accessToken":"xxxxxx"} /// auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc /// /// public static Task LogInWithAuthDataAsync(IDictionary data, string platform, AVUserAuthDataLogInOption options = null, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { if (options == null) { options = new AVUserAuthDataLogInOption(); } return AVUser.LogInWithAsync(platform, data, options.FailOnNotExist, cancellationToken); } public static Task LogInWithAuthDataAndUnionIdAsync( IDictionary authData, string platform, string unionId, AVUserAuthDataLogInOption options = null, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { if (options == null) { options = new AVUserAuthDataLogInOption(); } MergeAuthData(authData, unionId, options); return AVUser.LogInWithAsync(platform, authData, options.FailOnNotExist, cancellationToken); } public static Task LogInAnonymouslyAsync(CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { var data = new Dictionary { { "id", Guid.NewGuid().ToString() } }; var options = new AVUserAuthDataLogInOption(); return LogInWithAuthDataAsync(data, "anonymous", options, cancellationToken); } [Obsolete("please use LogInWithAuthDataAsync instead.")] public static Task LogInWithAsync(string authType, IDictionary data, CancellationToken cancellationToken) { return AVUser.LogInWithAsync(authType, data, false, cancellationToken); } /// /// link a 3rd auth account to the user. /// /// AVUser instance /// OAuth data, like {"accessToken":"xxxxxx"} /// auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc /// /// public Task AssociateAuthDataAsync(IDictionary data, string platform, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { return LinkWithAsync(platform, data, cancellationToken); } public Task AssociateAuthDataAndUnionIdAsync( IDictionary authData, string platform, string unionId, AVUserAuthDataLogInOption options = null, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { if (options == null) { options = new AVUserAuthDataLogInOption(); } MergeAuthData(authData, unionId, options); return LinkWithAsync(platform, authData, cancellationToken); } /// /// unlink a 3rd auth account from the user. /// /// AVUser instance /// auth platform,maybe "facebook"/"twiiter"/"weibo"/"weixin" .etc /// /// public Task DisassociateWithAuthDataAsync(string platform, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { return UnlinkFromAsync(platform, cancellationToken); } /// 合并为支持 AuthData 的格式 static void MergeAuthData(IDictionary authData, string unionId, AVUserAuthDataLogInOption options) { authData["platform"] = options.UnionIdPlatform; authData["main_account"] = options.AsMainAccount; authData["unionid"] = unionId; } #endregion } }