对用户进行身份验证 - Java SDK
Realm 提供了一个 API,用于使用任何已启用的身份验证提供者对用户进行身份验证。实例化一个 Credentials
对象,并将其传递给app.login()
或app.loginAsync()
方法,以验证用户登录身份并创建一个User
对象。 每个身份验证提供者都对应一个静态辅助方法,用于使用该身份验证提供者实例化Credentials
对象。
登录
您可以使用应用程序的io.realm.mongodb.App
类实例的app.login()
或app.loginAsync()
方法对用户进行身份验证。 app.login()
方法会阻止调用线程中的代码执行,直到提供的档案成功或失败对用户进行身份验证,而app.loginAsync()
方法允许继续执行,并使用保证执行的回调函数处理成功或失败在调用app.loginAsync()
的同一线程上。
如果成功, app.login()
方法将返回User
对象。 在事件的情况下, app.login()
方法会引发ObjectServerError
类型的异常。
将回调传递给app.loginAsync()
方法以处理成功或失败。 此回调接受类型为App.Result
的单个参数。 传递给回调的App.Result
对象的isSuccess()
方法会返回一个布尔值,指示操作是否成功。 在事件中,您可以使用getError()
方法查看导致失败的错误。
匿名用户
匿名身份验证提供者使用户能够使用不存储永久性个人信息的短期帐户登录您的应用程序。 要使用匿名身份验证登录,请调用Credentials.anonymous()
创建匿名档案,然后将生成的档案传递给app.login()
或app.loginAsync()
。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID) .build()); Credentials anonymousCredentials = Credentials.anonymous(); AtomicReference<User> user = new AtomicReference<User>(); app.loginAsync(anonymousCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated anonymously."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } });
val appID = YOUR_APP_ID // replace this with your App ID val app: App = App( AppConfiguration.Builder(appID) .build() ) val anonymousCredentials: Credentials = Credentials.anonymous() var user: User? app.loginAsync(anonymousCredentials) { if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated anonymously.") user = app.currentUser() } else { Log.e("AUTH", it.error.toString()) } }
电子邮件/密码用户
电子邮件/密码身份验证提供程序使用户能够使用电子邮件用户名和密码登录您的应用程序。 要使用电子邮件/密码身份验证进行登录,请使用用户的电子邮件和密码调用Credentials.emailPassword()
来创建电子邮件/密码档案。 然后将生成的档案传递给app.login()
或app.loginAsync()
。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID) .build()); Credentials emailPasswordCredentials = Credentials.emailPassword("<email>", "<password>"); AtomicReference<User> user = new AtomicReference<User>(); app.loginAsync(emailPasswordCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated using an email and password."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } });
val appID = YOUR_APP_ID // replace this with your App ID val app: App = App( AppConfiguration.Builder(appID) .build() ) val emailPasswordCredentials: Credentials = Credentials.emailPassword( "<email>", "<password>" ) var user: User? = null app.loginAsync(emailPasswordCredentials) { if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated using an email and password.") user = app.currentUser() } else { Log.e("AUTH", it.error.toString()) } }
API 密钥用户
API 密钥身份验证提供程序使用户能够使用客户端 SDK 中自动生成的 API 密钥登录您的应用程序。 要使用 API 密钥身份验证进行登录,请使用 API 密钥调用Credentials.apiKey()
来创建 API 密钥档案。 然后将生成的档案传递给app.login()
或app.loginAsync()
。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID) .build()); Credentials apiKeyCredentials = Credentials.apiKey("<key>"); AtomicReference<User> user = new AtomicReference<User>(); app.loginAsync(apiKeyCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated using an API Key."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } });
val appID = YOUR_APP_ID // replace this with your App ID val app: App = App( AppConfiguration.Builder(appID) .build() ) val apiKeyCredentials: Credentials = Credentials.apiKey("<key>") var user: User? = null app.loginAsync(apiKeyCredentials) { if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated using an API Key.") user = app.currentUser() } else { Log.e("AUTH", "Error logging in: ${it.error.toString()}") } }
自定义 JWT 用户
自定义 JSON Web 令牌身份验证提供程序使用户能够使用自定义JSON web token Web 令牌登录您的应用程序。 要使用自定义 JSON web token 身份验证进行登录,请使用自定义 JSON web token 调用Credentials.jwt()
来创建自定义 JSON web token 档案。 然后将生成的档案传递给app.login()
或app.loginAsync()
。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID) .build()); // fetch JWT from custom provider Credentials customJWTCredentials = Credentials.jwt("<token>"); AtomicReference<User> user = new AtomicReference<User>(); app.loginAsync(customJWTCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated using a custom JWT."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } });
val appID = YOUR_APP_ID // replace this with your App ID val app: App = App( AppConfiguration.Builder(appID) .build() ) // fetch JWT from custom provider val customJWTCredentials: Credentials = Credentials.jwt("<token>") var user: User? = null app.loginAsync(customJWTCredentials) { if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated using a custom JWT.") user = app.currentUser() } else { Log.e("AUTH", "Error logging in: ${it.error.toString()}") } }
自定义函数用户
自定义函数身份验证提供程序使用户能够使用应用中定义的Realm 函数登录到您的应用程序。 要使用自定义函数身份验证登录,请通过调用Credentials.customFunction()
创建档案。 customFunction()方法需要一个包含 Realm 身份验证函数使用的属性和值的文档。 例如,假设后端函数期望输入参数包含名为username
的字段,如下所示:
exports = async function(loginPayload) { const { username } = loginPayload; ... }
您传递给Credentials.customFunction()
的文档可能如下所示:
Document("username", "bob")
然后,将生成的档案传递给app.login()
或app.loginAsync()
。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID).build()); Credentials customFunctionCredentials = Credentials.customFunction(new org.bson.Document("username", "bob")); AtomicReference<User> user = new AtomicReference<User>(); app.loginAsync(customFunctionCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated using a custom function."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } });
val appID = YOUR_APP_ID // replace this with your App ID val app: App = App( AppConfiguration.Builder(appID) .build() ) val customFunctionCredentials: Credentials = Credentials.customFunction(org.bson.Document("username", "bob")) var user: User? = null app.loginAsync(customFunctionCredentials) { if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated using a custom function.") user = app.currentUser() } else { Log.e("AUTH", "Error logging in: ${it.error.toString()}") } }
Facebook 用户
Facebook身份验证提供者允许您使用用户现有的 Facebook 帐户通过 Facebook 应用对用户进行身份验证。
重要
请勿存储 Facebook 个人资料图片的 URL
Facebook 个人资料图片 URL 包含用户的访问令牌,用于授予该图像的权限。为了确保安全,请勿存储包含用户访问令牌的 URL。相反,在需要获取图像时,可直接从用户的元数据字段访问 URL。
按照 适用于 Android 的官方Facebook登录快速入门 设立应用程序的身份验证流程。在登录完成处理程序中,从Facebook LoginResult 获取已登录用户的访问权限令牌 。使用访问权限令牌创建Realm Facebook档案,然后将用户日志到您的Realm应用。
FacebookSdk.setApplicationId(YOUR_FACEBOOK_SDK_APP_ID); FacebookSdk.sdkInitialize(activity); CallbackManager callbackManager = CallbackManager.Factory.create(); LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() { public void onSuccess(LoginResult loginResult) { // Signed in successfully, forward credentials to MongoDB Realm. AccessToken accessToken = loginResult.getAccessToken(); Credentials facebookCredentials = Credentials.facebook(accessToken.getToken()); app.loginAsync(facebookCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully logged in to MongoDB Realm using Facebook OAuth."); } else { Log.e("AUTH", "Failed to log in to MongoDB Realm", it.getError()); } }); } public void onCancel() { Log.v("AUTH", "Facebook authentication cancelled."); } public void onError(FacebookException exception) { Log.e("AUTH", "Failed to authenticate using Facebook: " + exception.getMessage()); } } ); LoginManager.getInstance().logIn(activity, null);
FacebookSdk.setApplicationId(YOUR_FACEBOOK_SDK_APP_ID) FacebookSdk.sdkInitialize(activity) val callbackManager = CallbackManager.Factory.create() LoginManager.getInstance().registerCallback( callbackManager, object : FacebookCallback<LoginResult> { override fun onSuccess(loginResult: LoginResult) { // Signed in successfully, forward credentials to MongoDB Realm. val accessToken = loginResult.accessToken val facebookCredentials: Credentials = Credentials.facebook(accessToken.token) app.loginAsync(facebookCredentials) { if (it.isSuccess) { Log.v( "AUTH", "Successfully logged in to MongoDB Realm using Facebook OAuth." ) } else { Log.e("AUTH", "Failed to log in to MongoDB Realm", it.error) } } } override fun onCancel() { Log.v("AUTH", "Cancelled Facebook login") } override fun onError(exception: FacebookException) { Log.e("AUTH", "Failed to authenticate with Facebook: ${exception.message}") } })
Google 用户
重要
要使用现有 Google 账号登录,您必须为应用程序配置和启用 Google 身份验证提供程序。
要设置应用程序进行 Google 用户身份验证,请执行以下操作:
在 Google Cloud Platform 控制台 中 ,创建 OAuth2 。0类型为“Web 应用程序”的客户端 ID。
配置您的后台应用程序,以使用该客户端 ID 和相关的客户端密钥。
在后端启用 OpenID Connect。
使用 适用于 Android 的 Google 官方登录 对 Android 应用程序中的 Google 用户进行身份验证:
注意
下面的代码示例
有关这些说明的实施,请查看下面的代码块。
将 Google Sign-In for Android 依赖项添加到应用程序级别
build.gradle
的dependencies
区块:com.google.android.gms:play-services-auth:19.2.0 创建 GoogleSignInOptions 使用以下构建器选项:
使用
GoogleSignInOptions
GoogleSignInClient
通过 GoogleSignIn.getClient() 创建使用
GoogleSignInClient
创建能够触发 Google Sign-In 的Intent
。使用 registerForActivityResult() 以配置回调。回调应使用 GoogleSignIn.getSignedInAccountFromIntent()访问 Google 登录的结果:a
Task<GoogleSignInAccount>
。使用 launch() ActivityResultLauncher 的方法 在上一步中返回以启动 Google 登录。向
launch()
方法传递您的 Google 登录Intent
。使用
isSuccessful()
处理 Google 登录错误。访问任务结果( GoogleSignInAccount )和
getResult()
。使用
getIdToken()
访问GoogleSignInAccount
的 ID 令牌。使用Credentials.google()创建 Realm
Credentials
对象。 将 ID 令牌作为第一个参数传递,并将GoogleAuthType.ID_TOKEN作为第二个参数传递。使用app.loginAsync()或app.login()方法,通过令牌向 Atlas App Services 后端进行身份验证。
以下代码实现了此流程,从对loginWithGoogle()
的方法调用开始:
private void signInWithGoogle() { GoogleSignInOptions gso = new GoogleSignInOptions .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken("YOUR WEB APPLICATION CLIENT ID FOR GOOGLE AUTH") .build(); GoogleSignInClient googleSignInClient = GoogleSignIn.getClient(this, gso); Intent signInIntent = googleSignInClient.getSignInIntent(); ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { public void onActivityResult(ActivityResult result) { Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(result.getData()); handleSignInResult(task); } }); resultLauncher.launch(signInIntent); } private void handleSignInResult(Task<GoogleSignInAccount> completedTask) { try { if (completedTask.isSuccessful()) { GoogleSignInAccount account = completedTask.getResult(ApiException.class); String token = account.getIdToken(); Credentials googleCredentials = Credentials.google(token, GoogleAuthType.ID_TOKEN); app.loginAsync(googleCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully logged in to MongoDB Realm using Google OAuth."); } else { Log.e("AUTH", "Failed to log in to MongoDB Realm: ", it.getError()); } }); } else { Log.e("AUTH", "Google Auth failed: " + completedTask.getException().toString()); } } catch (ApiException e) { Log.w("AUTH", "Failed to log in with Google OAuth: " + e.getMessage()); } }
fun loginWithGoogle() { val gso = GoogleSignInOptions .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken("YOUR WEB APPLICATION CLIENT ID FOR GOOGLE AUTH") .build() val googleSignInClient = GoogleSignIn.getClient(this, gso) val signInIntent: Intent = googleSignInClient.signInIntent val resultLauncher: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(result.data) handleSignInResult(task) } resultLauncher.launch(signInIntent) } fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) { try { if (completedTask.isSuccessful) { val account: GoogleSignInAccount? = completedTask.getResult(ApiException::class.java) val token: String = account?.idToken!! val googleCredentials: Credentials = Credentials.google(token, GoogleAuthType.ID_TOKEN) app.loginAsync(googleCredentials) { if (it.isSuccess) { Log.v( "AUTH", "Successfully logged in to MongoDB Realm using Google OAuth." ) } else { Log.e("AUTH", "Failed to log in to MongoDB Realm", it.error) } } } else { Log.e("AUTH", "Google Auth failed: ${completedTask.exception}") } } catch (e: ApiException) { Log.e("AUTH", "Failed to authenticate using Google OAuth: " + e.message); } }
Apple 用户
Sign-in with Apple 身份验证提供程序使用户能够使用 Apple 提供的自定义令牌登录您的应用程序。 要使用 Sign-in with Apple 身份验证进行登录,请使用 Apple 提供的令牌调用Credentials.apple()
来创建 Sign-in with Apple 档案。 然后将生成的档案传递给app.login()
或app.loginAsync()
。
String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID) .build()); // fetch apple token using Apple SDK Credentials appleCredentials = Credentials.apple("<token>"); AtomicReference<User> user = new AtomicReference<User>(); app.loginAsync(appleCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated using Sign-in with Apple."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } });
val appID = YOUR_APP_ID // replace this with your App ID val app: App = App( AppConfiguration.Builder(appID) .build() ) // fetch IDToken using Apple SDK val appleCredentials: Credentials = Credentials.apple("<token>") var user: User? = null app.loginAsync(appleCredentials) { if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated using Sign-in with Apple.") user = app.currentUser() } else { Log.e("AUTH", "Error logging in: ${it.error.toString()}") } }
提示
如果您收到指示 token contains
an invalid number of segments
的 Login failed
错误,请验证您是否传递了 JWT 的 UTF-8 编码字符串版本。
离线登录
App Services 使用访问令牌和刷新令牌托管会话。客户端 SDK 提供托管令牌的逻辑,并向其发出请求。
当您的 Realm 应用程序对用户进行身份验证时,它会缓存该用户的档案。您可以检查是否存在现有用户档案以绕过登录流程并访问已缓存的用户。使用它可离线打开一个 Realm。
注意
初始登录需要网络连接
当用户注册您的应用或使用客户端上的现有帐户首次登录时,客户端必须具有网络连接。通过检查是否存在已缓存的用户档案,您可以离线打开 Realm,但前提是用户之前已在线登录。
// Log the user into the backend app. // The first time you login, the user must have a network connection. String appID = YOUR_APP_ID; // replace this with your App ID App app = new App(new AppConfiguration.Builder(appID) .build()); // Check for an existing user. // If the user is offline but credentials are // cached, this returns the existing user. AtomicReference<User> user = new AtomicReference<User>(); user.set(app.currentUser()); if (user.get() == null) { // If the device has no cached user // credentials, log them in. Credentials anonymousCredentials = Credentials.anonymous(); app.loginAsync(anonymousCredentials, it -> { if (it.isSuccess()) { Log.v("AUTH", "Successfully authenticated anonymously."); user.set(app.currentUser()); } else { Log.e("AUTH", it.getError().toString()); } }); }
// Log the user into the backend app. // The first time you login, the user must have a network connection. val appID = YOUR_APP_ID // replace this with your App ID val app = App( AppConfiguration.Builder(appID) .build() ) // Check for an existing user. // If the user is offline but credentials are // cached, this returns the existing user. val user = AtomicReference<User?>() user.set(app.currentUser()) if (user.get() == null) { // If the device has no cached user // credentials, log them in. val anonymousCredentials = Credentials.anonymous() app.loginAsync( anonymousCredentials ) { it: App.Result<User?> -> if (it.isSuccess) { Log.v("AUTH", "Successfully authenticated anonymously.") user.set(app.currentUser()) } else { Log.e("AUTH", it.error.toString()) } } }
获取用户访问令牌
当用户登录时,Atlas App Services 会为用户创建一个访问令牌,以为他们授予访问您应用的权限。Realm SDK 会自动管理访问令牌,在访问令牌过期时对其进行刷新,并在每次请求中为当前用户提供有效的访问令牌。Realm 不会自动对刷新令牌进行刷新。当刷新令牌过期后,用户必须重新登录。
如果在 SDK 外部发送请求,则需要在每个请求中包含用户的访问令牌,并在令牌过期时手动刷新令牌。
您可以在 SDK 中,通过用户的 Realm.User
对象来访问和刷新已登录用户的访问令牌,如下例所示:
// Gets a valid user access token to authenticate requests public String getValidAccessToken(User user) { // An already logged in user's access token might be stale. To // guarantee that the token is valid, refresh it if necessary. user.refreshCustomData(); return user.getAccessToken(); }
// Gets a valid user access token to authenticate requests fun getValidAccessToken(user: User?): String { // An already logged in user's access token might be stale. To // guarantee that the token is valid, refresh it if necessary. user!!.refreshCustomData() return user.accessToken }
注销用户
您可以使用user.logOut()
或user.logOutAsync()
方法注销任何用户,而不考虑用于登录的身份验证提供者。两种方法:
从设备中删除本地存储的用户档案
立即停止与用户 Realm 之间的任何双向同步
由于注销会停止同步,因此您应该仅在所有本地 Realm 更新上传到服务器后再注销。
user.get().logOutAsync( result -> { if (result.isSuccess()) { Log.v("AUTH", "Successfully logged out."); } else { Log.e("AUTH", result.getError().toString()); } });
user?.logOutAsync { if (it.isSuccess) { Log.v("AUTH", "Successfully logged out.") } else { Log.e("AUTH", it.error.toString()) } }