对用户进行身份验证 - Swift SDK
在此页面上
登录
匿名用户
如果您在App Services用户界面中启用了匿名身份验证,则用户无需提供任何身份信息即可立即日志您的应用。 以下代码演示了如何执行此操作:
let anonymousCredentials = Credentials.anonymous app.login(credentials: anonymousCredentials) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } }
电子邮件/密码用户
如果已启用电子邮件/密码身份验证,则可使用以下代码登录:
let email = "skroob@example.com" let password = "12345" app.login(credentials: Credentials.emailPassword(email: email, password: password)) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } }
API 密钥用户
如果已启用 API 密钥身份验证,则可使用以下代码登录:
let credentials = Credentials.userAPIKey("<api-key>") app.login(credentials: credentials) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } }
自定义函数用户
如果已启用自定义函数身份验证提供程序,则可以使用以下代码登录:
let params: Document = ["username": "bob"] app.login(credentials: Credentials.function(payload: params)) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } }
自定义 JWT 用户
如果已启用自定义 JWT 身份验证提供程序,则可以使用以下代码登录:
let credentials = Credentials.jwt(token: "<jwt>") app.login(credentials: credentials) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } }
Facebook 用户
Facebook身份验证提供者允许您使用用户现有的 Facebook 帐户通过 Facebook 应用对用户进行身份验证。
重要
请勿存储 Facebook 个人资料图片的 URL
Facebook 个人资料图片 URL 包含用户的访问令牌,用于授予该图像的权限。为了确保安全,请勿存储包含用户访问令牌的 URL。相反,在需要获取图像时,可直接从用户的元数据字段访问 URL。
按照 适用于iOS的官方Facebook登录快速入门 设立应用程序的身份验证流程。在登录完成处理程序中,使用登录用户的 访问权限令牌字符串 创建App Services Facebook档案 并将用户日志到您的App Services 应用。
// This example demonstrates login logic for FBSDK version 13.x. If you're using // a different version of FBSDK, you'll need to adapt this example for your version. let loginManager = LoginManager() loginManager.logIn(permissions: [ .email ]) { loginResult in switch loginResult { case .success(let grantedPermissions, let declinedPermissions, let accessToken): let credentials = Credentials.facebook(accessToken: accessToken!.tokenString) app.login(credentials: credentials) { result in DispatchQueue.main.async { switch result { case .failure(let error): print("Failed to log in to MongoDB Realm: \(error)") case .success(let user): print("Successfully logged in to MongoDB Realm using Facebook OAuth.") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } } } case .failed(let error): print("Facebook login failed: \(error)") case .cancelled: print("The user cancelled the login flow.") } }
Google 用户
重要
要使用现有 Google 账号登录,您必须为应用程序配置和启用 Google 身份验证提供程序。
遵循官方 Google Sign-In for iOS 集成指南 为应用程序设置身份验证流程。在登录完成处理程序中,创建 App Services Google 凭证并将用户登录到您的 App Services App。
您传递给凭证的值取决于您是否为提供程序启用了 OpenID Connect:
如果已启用 OpenID Connect,则传递
id_token
Google OAuth 响应中包含 的 为 Credentials.googleId(token:)。如果未启用 OpenID Connect,请传递用户的 服务器身份验证代码 到 Credentials.google(serverAuthCode:)。
func sign(_ signIn: GIDSignIn!, didSignInFor googleUser: GIDGoogleUser!, withError error: Error!) { if let error = error { print("\(error.localizedDescription)") return } // Get the ID token for the authenticated user so you can pass it to Realm let idToken = googleUser.authentication.idToken! let credentials = Credentials.googleId(token: idToken) app.login(credentials: credentials) { result in DispatchQueue.main.async { switch result { case .failure(let error): print("Failed to log in to MongoDB Realm: \(error)") case .success(let user): print("Successfully logged in to MongoDB Realm using Google OAuth.") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } } } }
func sign(_ signIn: GIDSignIn!, didSignInFor googleUser: GIDGoogleUser!, withError error: Error!) { if let error = error { print("\(error.localizedDescription)") return } // Upon first successful sign-in, forward serverAuthCode credentials to MongoDB Realm. // Upon subsequent sign-ins, this returns nil. let credentials = Credentials.google(serverAuthCode: googleUser.serverAuthCode!) app.login(credentials: credentials) { result in DispatchQueue.main.async { switch result { case .failure(let error): print("Failed to log in to MongoDB Realm: \(error)") case .success(let user): print("Successfully logged in to MongoDB Realm using Google OAuth.") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } } } }
Apple 用户
如果已启用 Apple 身份验证登录,则可以使用以下代码登录:
// Fetch IDToken via the Apple SDK let credentials = Credentials.apple(idToken: "<token>") app.login(credentials: credentials) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } }
提示
如果您收到指示 token contains
an invalid number of segments
的 Login failed
错误,请验证您是否传递了 JWT 的 UTF-8 编码字符串版本。
异步/等待登录
版本 10.15.0 新增内容。
App.login方法的异步/await 版本会异步返回用户或错误。
func login() async { do { let app = App(id: YOUR_APP_SERVICES_APP_ID) // Authenticate with the instance of the app that points // to your backend. Here, we're using anonymous login. let user = try await app.login(credentials: Credentials.anonymous) print("Successfully logged in user: \(user)") } catch { print("Failed to log in user: \(error.localizedDescription)") } }
从 Realm Swift SDK 10.15.0 和 10.16.0 版本开始,很多 Realm API 均支持 Swift“异步/等待”语法。项目必须符合以下要求:
Swift SDK 版本 | Swift 版本要求 | 支持的操作系统 |
---|---|---|
10.25.0 | Swift 5.6 | iOS 13.x |
10.15.0 或 10.16.0 | Swift 5.5 | iOS 15.x |
如果您的应用会在 async/await
上下文中访问 Realm,请使用 @MainActor
来标记此代码,从而避免出现与线程相关的崩溃。
离线登录
当您的 Realm 应用程序对用户进行身份验证时,它会缓存该用户的档案。您可以检查是否存在现有用户档案以绕过登录流程并访问已缓存的用户。使用它可离线打开一个 Realm。
注意
初始登录需要网络连接
当用户注册您的应用或使用客户端上的现有帐户首次登录时,客户端必须具有网络连接。通过检查是否存在已缓存的用户档案,您可以离线打开 Realm,但前提是用户之前已在线登录。
// Log the user into the backend app. // The first time you login, the user must have a network connection. func getUser() async throws -> User { // Check for an existing user. // If the user is offline but credentials are // cached, this returns the existing user. if let user = app.currentUser { return user } else { // If the device has no cached user // credentials, log them in. let app = App(id: YOUR_APP_SERVICES_APP_ID) let loggedInUser = try await app.login(credentials: Credentials.anonymous) return loggedInUser } } let user = try await getUser() var configuration = user.configuration(partitionValue: "Some Partition Value") // Open a Realm with this configuration. // If you do not require the app to download updates // before opening the realm, the realm just opens, even if // offline. let realm = try await Realm(configuration: configuration) print("Successfully opened realm: \(realm)")
获取用户访问令牌
Realm SDK 会自动管理访问令牌,在访问令牌过期时对其进行刷新,并在每次请求中为当前用户提供有效的访问令牌。
如果您在 SDK 外部发送请求,则必须在每个请求中包含用户的访问令牌。 在这种情况下,您必须在令牌过期时手动刷新令牌。 访问令牌会在30分钟后过期。
您可以对已登录用户调用.refreshCustomData()来刷新用户的身份验证会话。 然后,将 .accessToken
作为可在代码中使用的string返回。 您可以使用与此类似的函数来获取访问令牌:
func getValidAccessToken(user: User) async throws -> String { // An already logged in user's access token might be stale. To // guarantee that the token is valid, refresh it if necessary. try await user.refreshCustomData() return user.accessToken! }
这需要登录用户:
let app = App(id: YOUR_APP_SERVICES_APP_ID) let user = try await app.login(credentials: Credentials.anonymous) let accessToken = try await getValidAccessToken(user: user)
刷新令牌有效期
刷新令牌会在设定的时间段后过期。刷新令牌过期后,访问令牌将无法再刷新,用户必须重新登录。
如果刷新令牌在 Realm 打开后过期,则在用户再次登录之前设备无法进行同步。同步错误处理程序应实现在尝试同步时捕获令牌过期错误的逻辑,然后将用户重定向到登录流程。
有关配置刷新令牌过期时间的信息,请参阅 App Services 文档中的管理用户会话。
登出
登录后即可注销:
警告
当用户注销时,您无法再在用户已打开的任何已同步 Realm 中读取或写入数据。因此,在发起用户注销之前尚未完成的所有操作均无法成功完成,且可能会导致错误。以此方式失败的写入操作中的所有数据都将丢失。
app.currentUser?.logOut { (error) in // user is logged out or there was an error }