swift客户端库
supabase-swift在 GitHub 上查看本参考文档记录了 Supabase 的 Swift 库中可用的每个对象和方法,supabase-swift。您可以使用 supabase-swift 与您的 Postgres 数据库交互、监听数据库更改、调用 Deno Edge 函数、构建登录和用户管理功能以及管理大型文件。
安装
使用 Swift 包管理器安装#
您可以使用 Swift 包管理器安装 Supabase 包。
该包暴露了多个库,您可以选择添加所有库使用 Supabase,或者只添加其中的一些
认证实时Postgrest函数存储
如果您使用 Xcode,请按照 Apple 的依赖指南 将 supabase-swift 添加到您的项目中。当 Xcode 询问时,使用 https://github.com/supabase-community/supabase-swift.git 作为 url。
如果您不想要完整的 Supabase 环境,您可以添加单个包,例如 Functions、Auth、Realtime、Storage 或 PostgREST。
1let package = Package(2 ...3 dependencies: [4 ...5 .package(6 url: "https://github.com/supabase/supabase-swift.git",7 from: "2.0.0"8 ),9 ],10 targets: [11 .target(12 name: "YourTargetName",13 dependencies: [14 .product(15 name: "Supabase", // Auth, Realtime, Postgrest, Functions, or Storage16 package: "supabase-swift"17 ),18 ]19 )20 ]21)初始化
您可以使用 SupabaseClient 通过传递您的 项目 URL 和 项目密钥 来初始化 Supabase。您可以在 项目设置 → API 设置 中找到这些信息。Supabase 客户端是您进入 Supabase 所有功能的入口点,也是与我们 Supabase 生态系统中的所有内容交互的最简单方法。
1import Supabase23let client = SupabaseClient(supabaseURL: URL(string: "https://xyzcompany.supabase.co")!, supabaseKey: "publishable-or-anon-key")获取数据
1struct Instrument: Decodable {2 let id: Int3 let name: String4}56let instruments: [Instrument] = try await supabase7 .from("instruments")8 .select()9 .execute()10 .value插入数据
1struct Instrument: Encodable {2 let id: Int3 let name: String4}56let instrument = Instrument(id: 1, name: "ukelele")78try await supabase9 .from("instruments")10 .insert(instrument)11 .execute()更新数据
update()始终应与 过滤器 结合使用,以定位您希望更新的项目。
1try await supabase2 .from("instruments")3 .update(["name": "piano"])4 .eq("id", value: 1)5 .execute()更新或插入数据
- 要使用 upsert,必须在
values中包含主键。
1struct Instrument: Encodable {2 let id: Int3 let name: String4}5try await supabase6 .from("instruments")7 .upsert(Instrument(id: 1, name: "piano"))8 .execute()删除数据
1try await supabase2 .from("instruments")3 .delete()4 .eq("id", value: 1)5 .execute()调用 Postgres 函数
您可以将 Postgres 函数作为远程过程调用来调用,这些是在您的数据库中可以从任何地方执行的逻辑。当逻辑很少更改时,函数很有用——例如用于密码重置和更新。
1create or replace function hello_world() returns text as $$2 select 'Hello world';3$$ language sql;1let value: String = try await supabase2 .rpc("hello_world")3 .execute()4 .value使用过滤器
过滤器允许你仅返回匹配特定条件的行。
过滤器可用于 select()、update()、upsert() 和 delete() 查询。
如果 Postgres 函数返回表响应,您也可以应用过滤器。
在您自己的类型中实现 URLQueryRepresentable 协议,以便能够将其用作过滤器值。
支持的过滤器是:eq、neq、gt、gte、lt、lte、like、ilike、is、in、cs、cd、sl、sr、nxl、nxr、adj、ov、fts、plfts、phfts、wfts。请在 PostgREST 中查看可用的运算符。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .eq("name", value: "The Shire") // Correct56try await supabase7 .from("citites")8 .eq("name", value: "The Shire") // Incorrect9 .select("name, country_id")列等于一个值
仅匹配 column 等于 value 的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .eq("name", value: "The shire")列不等于一个值
仅匹配 column 不等于 value 的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .neq("name", value: "Paris")列大于一个值
仅匹配 column 大于 value 的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .gt("country_id", value: 250)列大于或等于一个值
仅匹配 column 大于或等于 value 的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .gte("country_id", value: 250)列小于一个值
仅匹配 column 小于 value 的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .lt("country_id", value: 250)列小于或等于一个值
仅匹配 column 小于或等于 value 的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .lte("country_id", value: 250)列匹配一个模式
仅匹配 column 与 pattern 区分大小写匹配的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .like("name", pattern: "%la%")列匹配一个不区分大小写的模式
仅匹配 column 与 pattern 不区分大小写匹配的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .ilike("name", pattern: "%la%")列是一个值
仅匹配 column IS value 的行。对于非空值,这等同于 eq 过滤器。对于空值,请使用此过滤器代替 eq。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .is("name", value: nil)列在一个数组中
仅匹配 column 包含在 values 数组中的行。
1try await supabase2 .from("cities")3 .select("name, country_id")4 .in("name", values: ["Rio de Janeiro", "San Francisco"])列包含数组中的每个元素
仅匹配 column 包含 value 中出现的每个元素的行。
1try await supabase2 .from("cities")3 .select("name, main_exports")4 .contains("main_exports", value: ["oil"])具有共同元素
仅匹配 column 和 value 具有共同元素的行。
1try await supabase2 .from("cities")3 .select("name, main_exports")4 .overlaps("main_exports", value: ["exports", "tourism"])匹配关联值
1try await supabase2 .from("instruments")3 .select("name")4 .match(["id": 2, "name": "viola"])不匹配过滤器
查找不满足过滤器的所有行。
-
.not()要求您使用原始 PostgREST 语法 用于过滤器名称和值。1.not("name", operator: .eq, value: "violin")2.not("arraycol", operator: .cs, value: #"{"a","b"}"#) // Use Postgres array {} for array column and 'cs' for contains.3.not("rangecol", operator: .cs, value: "(1,2]") // Use Postgres range syntax for range column.4.not("id", operator: .in, value: "(6,7)") // Use Postgres list () and 'in' for in_ filter.5.not("id", operator: .in, value: "(\(mylist.join(separator: ",")))") // You can insert a Swift list array.
1try await supabase2 .from("instruments")3 .select()4 .not("name", operator: .is, value: "")5 .execute()匹配至少一个过滤器
or() 要求您使用原始 PostgREST 语法用于过滤器名称和值。
1.or(#"id.in.(5,6,7), arraycol.cs.{"a","b"}"#) // Use `()` for `in` filter, `{}` for array values and `cs` for `contains()`.2.or(#"id.in.(5,6,7), arraycol.cd.{"a","b"}"#) // Use `cd` for `containedBy()`1try await supabase2 .from("instruments")3 .select("name")4 .or("id.eq.2,name.eq.cello")匹配过滤器
filter() 期望您使用原始 PostgREST 语法来获取过滤器的值。
1.filter("id", operator: "in", value: "(5,6,7)") // Use `()` for `in` filter2.filter("arraycol", operator: "cs", value: #"{"a","b"}"#) // Use `cs` for `contains()`, `{}` for array values1try await supabase2 .from("instruments")3 .select()4 .filter("name", operator: "in", value: #"("cello","guzheng")"#)使用修饰符
过滤器在行级别起作用——它们允许您仅返回匹配特定条件的行,而不会更改行的形状。修饰符是所有不符合该定义的内容——允许您更改响应的格式(例如,返回 CSV 字符串)。
修饰符必须在过滤器之后指定。某些修饰符仅适用于返回行的查询(例如,select() 或返回表响应的函数的 rpc())。
插入后返回数据
对查询结果执行 SELECT。
1try await supabase2 .from("instruments")3 .upsert(InstrumentModel(id: 1, name: "piano"))4 .select()5 .execute()对结果进行排序
按列对查询结果进行排序。
1try await supabase2 .from("instruments")3 .select("id, name")4 .order("id", ascending: false)5 .execute()限制返回的行数
按计数限制查询结果。
1try await supabase2 .from("instruments")3 .select("id, name")4 .limit(1)5 .execute()将查询限制在一个范围内
按 from 和 to 包含性地限制查询结果。
1try await supabase2 .from("instruments")3 .select("name")4 .range(from: 0, to: 1)5 .execute()检索一行数据
默认情况下,PostgREST 将所有 JSON 结果返回到一个数组中,即使只有一个项目,也请使用 single() 将第一个对象返回而不包含在数组中。
1try await supabase2 .from("instruments")3 .select("name")4 .limit(1)5 .single()6 .execute()检索为 CSV
1try await supabase2 .from("instruments")3 .select()4 .csv()5 .execute()使用 explain
为了调试慢查询,你可以使用 explain() 方法获取查询的 Postgres EXPLAIN 执行计划。这适用于任何查询,甚至适用于 rpc() 或写入。
Explain 默认情况下未启用,因为它可能会泄露数据库中的敏感信息。最好仅在测试环境中使用,但如果您希望在生产环境中使用,可以通过使用 `pre-request` 函数提供额外的保护。
请遵循 性能调试指南 以在您的项目上启用此功能。
1try await supabase2 .from("instruments")3 .select()4 .explain()5 .execute()6 .value概述
可以通过 supabase.auth 命名空间访问身份验证方法。
处理深层链接#
UIKit 应用生命周期#
1public func application(2 _ application: UIApplication,3 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?4) -> Bool {5 if let url = launchOptions?[.url] as? URL {6 supabase.auth.handle(url)7 }89 return true10}1112func application(13 _ app: UIApplication,14 open url: URL,15 options: [UIApplication.OpenURLOptionsKey: Any]16) -> Bool {17 supabase.auth.handle(url)18 return true19}2021#### UIKit app lifecycle with scenes2223In your `SceneDelegate.swift`:2425```swift26func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {27 guard let url = URLContexts.first?.url else { return }28 supabase.auth.handle(url)29}SwiftUI 应用生命周期#
在您的 AppDelegate.swift 中
1SomeView()2 .onOpenURL { url in3 supabase.auth.handle(url)4 }1let supabase = SupabaseClient(supabaseURL: URL(string: "https://xyzcompany.supabase.co")!, supabaseKey: "publishable-or-anon-key")2let auth = supabase.auth创建新用户
- 默认情况下,用户需要在登录前验证其电子邮件地址。要关闭此功能,请在 您的项目中 禁用 确认电子邮件。
- **确认电子邮件** 确定用户在注册后是否需要确认其电子邮件地址。
- 如果启用了 **确认电子邮件**,则会返回一个 `user`,但 `session` 为 null。
- 如果禁用了 **确认电子邮件**,则会同时返回 `user` 和 `session`。
- 当用户确认其电子邮件地址时,默认情况下他们将被重定向到
SITE_URL。您可以在 您的项目 中修改您的SITE_URL或添加其他重定向 URL。 - 如果对已存在的已确认用户调用 signUp()
- 当在 您的项目 中同时启用 **确认电子邮件** 和 **确认电话**(即使电话提供程序已禁用)时,将返回一个混淆/虚假的用户对象。
- 当 **确认电子邮件** 或 **确认电话**(即使电话提供程序已禁用)中的任何一个被禁用时,将返回错误消息 `User already registered`。
- 要获取当前登录的用户,请参阅
getUser()。
参数
- email可选字符串
必须提供
email或phone中的一个。 - phone可选字符串
必须提供
email或phone中的一个。 - passwordString
- data可选JSONObject
一个自定义数据对象,用于存储其他用户元数据。
- redirectTo可选URL
仅用于电子邮件注册。嵌入在电子邮件链接中的重定向 URL。必须是您 Supabase 实例配置的重定向 URL。
- captchaToken可选字符串
1try await supabase.auth.signUp(2 email: "example@email.com",3 password: "example-password"4)监听认证事件
- 订阅用户会话上发生的重要事件。
- 已发出事件
INITIAL_SESSION- 在构造 Supabase 客户端并从存储加载初始会话后立即发出。
SIGNED_IN- 每次确认或重新建立用户会话时发出,包括用户登录时。
- 不要假设此事件何时触发,即使用户已经登录也可能发生。请检查附加到事件的用户对象,以查看是否已登录新用户并更新您的应用程序的 UI。
SIGNED_OUT- 用户注销时发出。这可能是因为
- 调用
supabase.auth.signOut()。 - 用户的会话因任何原因已过期
- 用户在另一设备上注销。
- 会话已达到其时间限制或不活动超时。
- 用户在启用每个用户单个会话的情况下,在另一设备上登录。
- 请查看 用户会话 文档以获取更多信息。
- 调用
- 使用此功能清理您的应用程序与用户关联的任何本地存储。
- 用户注销时发出。这可能是因为
TOKEN_REFRESHED- 每次为已登录用户获取新的访问和刷新令牌时发出。
- 最好实践和强烈建议提取访问令牌 (JWT) 并将其存储在内存中以供您的应用程序进一步使用。
- 避免为同一目的频繁调用
supabase.auth.session。
- 避免为同一目的频繁调用
- 有一个后台进程跟踪会话应该何时刷新,因此您将始终通过监听此事件接收有效的令牌。
- 此事件的频率与您的项目上配置的 JWT 过期限制有关。
USER_UPDATED- 每次
supabase.auth.update(user:)方法成功完成时发出。监听它以根据新的个人资料信息更新您的应用程序的 UI。
- 每次
PASSWORD_RECOVERY- 当用户访问 URL 中包含密码恢复链接的页面时,而不是
SIGNED_IN事件发出。 - 使用它向用户显示一个 UI,用户可以在其中 重置他们的密码。
- 当用户访问 URL 中包含密码恢复链接的页面时,而不是
1// Using AsyncStream2for await (event, session) in await supabase.auth.authStateChanges {3 print(event, session)4}56// Using Closure7let subscription = await supabase.auth.onAuthStateChange { event, session in8 print(event, session)9}1011// call remove() to remove subscription12subscription.remove()创建匿名用户
- 返回一个匿名用户
- 建议为匿名注册设置验证码以防止滥用。您可以在 `options` 参数中传递验证码令牌。
1let session = try await supabase.auth.signInAnonymously(captchaToken: captchaToken)登录用户
- 需要电子邮件和密码或电话号码和密码。
参数
- email可选字符串
必须提供
email或phone中的一个。 - phone可选字符串
必须提供
email或phone中的一个。 - passwordString
- captchaToken可选字符串
1try await supabase.auth.signIn(2 email: "example@email.com",3 password: "example-password"4)使用 ID Token 登录 (原生登录)
1let session = try await supabase.auth.signInWithIdToken(2 credentials: OpenIDConnectCredentials(3 provider: .apple,4 idToken: "your-id-token",5 nonce: "your nonce"6 )7)通过 OTP 登录用户
- 需要电子邮件或电话号码。
- 此方法用于无密码登录,其中 OTP 会发送到用户的电子邮件或电话号码。
- 如果用户不存在,
signInWithOTP()将注册用户。要限制此行为,您可以将shouldCreateUser设置为 `false``。 - 如果您使用的是电子邮件,您可以配置是否希望用户接收 magiclink 或 OTP。
- 如果您使用的是电话,您可以配置是否希望用户接收 OTP。
- magic link 的目标 URL 由
SITE_URL确定。 - 请参阅 重定向 URL 和通配符 以将其他重定向 URL 添加到您的项目。
- 魔力链接和 OTP 共享相同的实现方式。要向用户发送一次性代码而不是魔力链接,请修改魔力链接电子邮件模板,包含
{{ .Token }}而不是{{ .ConfirmationURL }}。 - 有关配置 WhatsApp 登录的详细信息,请参阅我们的 Twilio 电话认证指南。
参数
- email可选字符串
必须提供
email或phone中的一个。 - phone可选字符串
必须提供
email或phone中的一个。 - redirectTo可选字符串
仅用于电子邮件注册。嵌入在电子邮件链接中的重定向 URL。必须是您 Supabase 实例配置的重定向 URL。
- channel可选MessagingChannel
用于发送消息的通道。仅用于电话注册。
- shouldCreateUser可选布尔值
如果用户不存在,是否创建用户。默认为 true。
- data可选JSONObject
一个自定义数据对象,用于存储其他用户元数据。
- captchaToken可选字符串
1try await supabase.auth.signInWithOTP(2 email: "example@email.com",3 redirectTo: URL(string: "my-app-scheme://")!4)通过 OAuth 登录用户
- 此方法用于使用第三方提供程序登录。
- Supabase 支持许多不同的 第三方提供程序。
参数
- provider提供商
第三方提供商。
- redirectTo可选URL
用户确认后要发送到的 URL。
- scopes可选字符串
授予 OAuth 应用程序的空格分隔的权限列表。
- queryParams可选[(name: String, value: String?)]
额外的查询参数。
- configure可选Callback
用于外部打开 OAuth 流程的自定义配置回调函数。
1let session = try await supabase.auth.signInWithOAuth(2 provider: .github3) { (session: ASWebAuthenticationSession) in4 // customize session5}通过 SSO 登录用户
- 在您可以使用此方法之前,您需要 建立与身份提供程序的连接。使用 CLI 命令 来执行此操作。
- 如果您已将电子邮件域与身份提供程序关联,则可以使用 `domain` 属性启动登录流程。
- 如果您需要使用不同的方式使用身份提供程序启动身份验证流程,可以使用 `providerId` 属性。例如
- 将特定的用户电子邮件地址与身份提供程序映射。
- 使用不同的提示来识别用户要使用的身份提供程序,例如公司特定的页面、IP 地址或其他跟踪信息。
参数
- providerId可选字符串
SSO 提供商的 UUID。
providerId或domain之一是必需的。 - domain可选字符串
使用 SSO 的组织的域名。
providerId或domain之一是必需的。 - redirectTo字符串
用户登录后要重定向到的 URL。必须是您 Supabase 实例配置的重定向 URL。
- captchaToken字符串
1// You can extract the user's email domain and use it to trigger the2 // authentication flow with the correct identity provider.34 let url = try await await supabase.auth.signInWithSSO{5 domain: "company.com"6 }78 // Open the URL using your preferred method to complete sign-in process.9 UIApplication.shared.open(url)从经过验证的 JWT 获取用户声明
- 验证 JWT 并提取其声明。
- 对于对称 JWT (HS256),服务器端通过
getUser()API 进行验证。 - 对于非对称 JWT (RS256),客户端使用 Apple Security 框架进行验证。
- 为了获得最佳性能,使用在具有相同存储键的所有客户端之间共享的全局 JWKS 缓存。
- 当未找到 JWK 时,回退到服务器端验证以自动处理密钥轮换。
- JWKS 缓存具有 10 分钟的 TTL(生存时间)。
参数
- jwt可选字符串
要验证的 JWT。如果未提供,则使用当前会话中的访问令牌。
- options可选GetClaimsOptions
JWT 验证选项。可以指定
allowExpired以跳过过期检查,并指定jwks以提供自定义 JSON Web Key Set。
1let response = try await supabase.auth.getClaims()2print("User ID: \(response.claims.sub ?? "N/A")")3print("Email: \(response.claims.email ?? "N/A")")4print("Role: \(response.claims.role ?? "N/A")")注销用户
- 为了使用 `signOut()` 方法,用户需要先登录。
1try await supabase.auth.signOut()通过 OTP 验证并登录
verifyOTP方法接受不同类型的验证。如果使用电话号码,则类型可以是sms或phone_change。如果使用电子邮件地址,则类型可以是以下之一:signup、magiclink、recovery、invite、email_change或email。- 应根据在调用
verifyOTP注册/登录用户之前调用的相应身份验证方法来确定使用的验证类型。
参数
- email可选字符串
必须提供
phone、email或token_hash之一。 - phone可选字符串
必须提供
phone、email或token_hash之一。 - token_hash可选字符串
用户电子邮件链接中的令牌哈希。必须提供
phone、email或token_hash之一。 - typeEmailOTPType | MobileOTPType
- token可选字符串
发送给用户的 OTP。如果使用
phone或email,则需要。 - redirectTo可选URL
用户确认后要重定向到的 URL。必须在您配置的重定向 URL 中。
- captchaToken可选字符串
已弃用。
1try await supabase.auth.verifyOTP(2 phone: "+13334445555",3 token: "123456",4 type: .sms5)获取会话
- 返回会话,如果需要则刷新它。如果找不到会话,则会抛出
GoTrueError.sessionNotFound错误。
1try await supabase.auth.session获取新的会话
- 此方法将刷新会话,无论当前会话是否过期。
1let session = try await supabase.auth.refreshSession()获取用户
- 此方法对于检查用户是否已授权很有用,因为它会在服务器上验证用户的访问令牌 JWT。
- 从数据库而不是本地会话中获取用户对象。
- 仅当您需要最新的用户数据时才应使用此方法。为了获得更快的速度,建议使用
session.user。
1let user = try await supabase.auth.user()更新用户
- 为了使用 `updateUser()` 方法,用户需要先登录。
- 默认情况下,电子邮件更新会将确认链接发送到用户的当前电子邮件和新电子邮件。要仅将确认链接发送到用户的新的电子邮件,请在您项目的 电子邮件身份验证提供程序设置 中禁用 **安全电子邮件更改**。
1try await supabase.auth.update(user: UserAttributes(email: "new@email.com"))获取与用户关联的身份
- 需要用户登录才能调用
userIdentities()。
1let identities = try await supabase.auth.userIdentities()将身份与用户关联
- 必须从您的 项目身份验证设置 中启用 **启用手动链接** 选项。
- 需要先登录才能调用 `linkIdentity()`。
- 如果候选身份已链接到现有用户或另一个用户,`linkIdentity()` 将失败。
1try await supabase.auth.linkIdentity(provider: provider)将身份从用户取消关联
- 必须从您的 项目身份验证设置 中启用 **启用手动链接** 选项。
- 用户需要已登录才能调用
unlinkIdentity()。 - 用户必须至少拥有 2 个身份才能取消关联一个身份。
- 要取消关联的身份必须属于该用户。
1// retrieve all identities linked to a user2let identities = try await supabase.auth.userIdentities()34// find the google identity5let googleIdentity = identities.first {6 $0.provider == .google7}89// unlink the google identity10try await supabase.auth.unlinkIdentity(googleIdentity)发送密码重新认证 nonce
- 当需要更新用户的密码时,此方法与
update(user:)一起使用。 - 如果您要求用户在更新密码之前重新进行身份验证,则需要在您的 项目电子邮件提供程序设置中启用 安全密码更改 选项。
- 如果启用了安全密码更改并且用户最近未登录,则用户只需要在更新密码之前重新进行身份验证。如果会话在过去 24 小时内创建,则认为用户最近已登录。
- 此方法会将 nonce 发送到用户的电子邮件。如果用户没有确认的电子邮件地址,该方法会将 nonce 发送到用户的确认的电话号码。
1try await supabase.auth.reauthenticate()重新发送 OTP
- 重新发送注册确认、电子邮件更改或电话号码更改电子邮件给用户。
- 可以通过再次调用
signInWithOTP()方法重新发送无密码登录。 - 可以通过再次调用
resetPasswordForEmail()方法重新发送密码恢复电子邮件。 - 只有在进行了初始注册、电子邮件更改或电话号码更改请求后,此方法才会重新发送电子邮件或电话 OTP 给用户。
- 您可以使用
emailRedirectTo选项在重新发送电子邮件链接时指定重定向 URL。
1try await supabase.auth.resend(2 email: "email@example.com",3 type: .signup,4 emailRedirectTo: URL(string: "my-app-scheme://")5)设置会话数据
setSession()接收一个刷新令牌并使用它来获取一个新会话。- 刷新令牌只能使用一次来获取新会话。
- 刷新令牌轮换默认在所有项目上启用,以防止重放攻击。
- 您可以配置
REFRESH_TOKEN_REUSE_INTERVAL,它提供了一个简短的时间窗口,在此期间可以在并发或离线问题的情况下多次使用相同的刷新令牌。
1try await supabase.auth.setSession(accessToken: "access_token", refreshToken: "refresh_token")将授权码交换为会话
- 当客户端选项中的
flowType设置为pkce时使用。
1try await supabase.auth.exchangeCodeForSession(authCode: "34e770dd-9ff9-416c-87fa-43b31d7ef225")启动自动刷新会话(非浏览器)
启动自动会话刷新过程。
1supabase.auth.startAutoRefresh()停止自动刷新会话(非浏览器)
停止自动会话刷新过程。
1supabase.auth.stopAutoRefresh()认证 MFA
本节包含通常用于多因素身份验证 (MFA) 的方法,并在 supabase.auth.mfa 命名空间下调用。
目前,我们仅支持基于时间的 One-Time Password (TOTP) 作为第二个因素。我们不支持恢复代码,但允许用户注册超过 1 个 TOTP 因素,上限为 10 个。
拥有第二个 TOTP 因素用于恢复,可以减轻用户存储恢复代码的负担。它还可以减少攻击面,因为通常会生成多个恢复代码,而不仅仅是 1 个备份 TOTP 因素。
注册因素
- 目前,
totp是唯一支持的factorType。返回的id应用于创建挑战。 - 要创建挑战,请参阅
mfa.challenge()。 - 要验证挑战,请参阅
mfa.verify()。 - 要一步创建和验证挑战,请参阅
mfa.challengeAndVerify()。
1let response = try await supabase.auth.mfa.enroll(2 params: MFAEnrollParams(3 issuer: "optional issuer",4 friendlyName: "optional friendly name"5 )6)78// Use the id to create a challenge.9// The challenge can be verified by entering the code generated from the authenticator app.10// The code will be generated upon scanning the qrCode or entering the secret into the authenticator app.11let id = response.id12let type = response.type13let qrCode = response.totp?.qrCode14let secret = response.totp?.secret15let uri = response.totp?.uri创建挑战
- 在创建挑战之前,需要一个已注册的因素。
- 要验证挑战,请参阅
mfa.verify()。
1let response = try await supabase.auth.mfa.challenge(2 params: MFAChallengeParams(3 factorId: "34e770dd-9ff9-416c-87fa-43b31d7ef225"4 )5)验证挑战
- 在验证挑战之前,请创建挑战。
1let session = try await supabase.auth.mfa.verify(2 params: MFAVerifyParams(3 factorId: "34e770dd-9ff9-416c-87fa-43b31d7ef225",4 challengeId: "4034ae6f-a8ce-4fb5-8ee5-69a5863a7c15",5 code: "123456"6 )7)创建并验证挑战
- 在调用
challengeAndVerify()之前,需要一个已注册的因素。 - 一步执行
mfa.challenge()和mfa.verify()。
1let session = try await supabase.auth.mfa.challengeAndVerify(2 params: MFAChallengeAndVerifyParams(3 factorId: "34e770dd-9ff9-416c-87fa-43b31d7ef225",4 code: "123456"5 )6)取消注册因素
- 自 v2.41.1 以来,取消注册响应使用
id代替factorId以匹配服务器响应格式。如果从早期版本升级,请更新您的代码以使用response.id。
1let response = try await supabase.auth.mfa.unenroll(2 params: MFAUnenrollParams(3 factorId: "34e770dd-9ff9-416c-87fa-43b31d7ef225"4 )5)6print(response.id) // ID of the unenrolled factor获取身份验证器保证级别
- 身份验证器保证级别 (AAL) 是身份验证机制强度的度量。
- 在 Supabase 中,具有
aal1的 AAL 指的是第一因素身份验证,例如电子邮件和密码或 OAuth 登录,而aal2指的是第二因素身份验证,例如基于时间的一次性密码 (TOTP)。 - 如果用户具有经过验证的因素,则
nextLevel字段将返回aal2,否则,将返回aal1。
1let aal = try await supabase.auth.mfa.getAuthenticatorAssuranceLevel()2let currentLevel = aal.currentLevel3let nextLevel = aal.nextLevel4let currentAuthenticationMethods = aal.currentAuthenticationMethods认证 Admin
supabase.auth.admin命名空间下的任何方法都需要一个service_role密钥。- 这些方法被认为是管理方法,应在受信任的服务器上调用。切勿在浏览器中公开你的
service_role密钥。
1import Supabase23let supabase = SupabaseClient(4 supabaseURL: supabaseURL,5 supabaseKey: serviceRoleKey6)78// Access auth admin api9let adminAuthClient = supabase.auth.admin获取用户
按 ID 获取用户。
getUserById()方法需要用户的 ID。
1let user = try await supabase.auth.admin.getUserById(2 "715ed5db-f090-4b8c-a067-640ecee36aa0"3)列出所有用户
列出系统中的所有用户。
1let users = try await supabase.auth.admin.listUsers()创建用户
创建一个新用户。
1let user = try await supabase.auth.admin.createUser(2 attributes: AdminUserAttributes(3 email: "user@email.com",4 password: "password",5 emailConfirm: true6 )7)删除用户
deleteUser()方法需要用户的 ID,它映射到auth.users.id列。
1try await supabase.auth.admin.deleteUser(2 id: "715ed5db-f090-4b8c-a067-640ecee36aa0"3)发送电子邮件邀请链接
向用户的电子邮件地址发送邀请链接。
1let user = try await supabase.auth.admin.inviteUserByEmail(2 "user@email.com",3 data: ["role": "admin"],4 redirectTo: URL(string: "https://example.com/welcome")5)更新用户
按 ID 更新用户。
1let user = try await supabase.auth.admin.updateUserById(2 "715ed5db-f090-4b8c-a067-640ecee36aa0",3 attributes: AdminUserAttributes(4 email: "newemail@email.com"5 )6)调用 Supabase 边缘函数。
调用 Supabase Edge 函数。
- 需要 Authorization 标头。
- 当您传递一个主体给您的函数时,我们自动为
String和Data附加 Content-Type 标头。如果它不匹配任何这些类型,我们假定有效负载是json,对其进行序列化并将Content-Type标头附加为application/json。您可以通过传递自己的Content-Type标头来覆盖此行为。 - 当指定区域时,将设置
x-region标头和forceFunctionRegion查询参数,以确保正确的函数路由。
1struct Response: Decodable {2 // Expected response definition3}45let response: Response = try await supabase.functions6 .invoke(7 "hello",8 options: FunctionInvokeOptions(9 body: ["foo": "bar"]10 )11 )订阅频道
- 默认情况下,广播和存在性对所有项目都已启用。
- 默认情况下,由于数据库性能和安全问题,对数据库更改的侦听在新项目中是禁用的。你可以通过管理实时的 复制 来启用它。
- 你可以通过将表的
REPLICA IDENTITY设置为FULL(例如,ALTER TABLE your_table REPLICA IDENTITY FULL;)来接收更新和删除的“先前”数据。 - 行级安全性不适用于删除语句。当启用 RLS 并且复制标识设置为 full 时,仅将主键发送给客户端。
- 使用 AsyncStream 或回调来监听更改。
1let channel = supabase.channel("room1")23let broadcastStream = channel.broadcastStream(event: "cursor-pos")45await channel.subscribe()67Task {8 for await message in broadcastStream {9 print("Cursor position received", message)10 }11}1213await channel.broadcast(14 event: "cursor-pos",15 message: [16 "x": .double(.random(in: 0...1)),17 "y": .double(.random(in: 0...1))18 ]19)取消订阅频道
取消订阅并从实时客户端中删除实时通道。
- 删除一个通道是维护项目实时服务性能以及数据库性能的好方法,如果您正在监听 Postgres 更改。
- Supabase 会在客户端断开连接后 30 秒自动处理清理,但未使用的通道可能会导致更多客户端同时订阅时性能下降。
- 如果您删除了所有通道,客户端将自动断开实时 websocket 连接。这可以在实时配置中通过将
disconnectOnNoSubscriptions设置为 false 来禁用。
1let channel = supabase.channel("channelId")23//...4await supabase.removeChannel(channel)取消订阅所有频道
取消订阅并从实时客户端删除所有实时通道。
- 删除频道是维护项目实时服务性能以及数据库性能的好方法(如果你正在侦听 Postgres 更改)。Supabase 会在客户端断开连接 30 秒后自动处理清理,但未使用的频道可能会导致更多客户端同时订阅而导致性能下降。
- 如果您删除了所有通道,客户端将自动断开实时 websocket 连接。这可以在实时配置中通过将
disconnectOnNoSubscriptions设置为 false 来禁用。
1await supabase.removeAllChannels()获取所有频道
返回所有实时通道。
1let channels = supabase.channels文件存储
本节包含处理文件存储桶的方法。
列出所有存储桶
- 所需的 RLS 策略权限
buckets表权限:selectobjects表权限:无
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase.storage2 .listBuckets()检索存储桶
- 所需的 RLS 策略权限
buckets表权限:selectobjects表权限:无
- 请参阅 存储指南,了解访问控制的工作方式
1let bucket = try await supabase.storage2 .getBucket("avatars")创建存储桶
- 所需的 RLS 策略权限
buckets表权限:insertobjects表权限:无
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase.storage2 .createBucket(3 "avatars",4 options: BucketOptions(5 public: false,6 allowedMimeTypes: ["image/png"],7 fileSizeLimit: 10248 )9 )清空存储桶
- 所需的 RLS 策略权限
buckets表权限:selectobjects表权限:select和delete
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase.storage2 .emptyBucket("avatars")更新存储桶
- 所需的 RLS 策略权限
buckets表权限:select和updateobjects表权限:无
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase.storage2 .updateBucket(3 "avatars",4 options: BucketOptions(5 public: false,6 fileSizeLimit: 1024,7 allowedMimeTypes: ["image/png"]8 )9 )删除存储桶
- 所需的 RLS 策略权限
buckets表权限:select和deleteobjects表权限:无
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase.storage2 .deleteBucket("avatars")上传文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:仅当上传新文件时为insert,当更新文件时为select、insert和update
- 请参阅 存储指南,了解访问控制的工作方式
1let fileName = "avatar1.png"23try await supabase.storage4 .from("avatars")5 .upload(6 path: "public/\(fileName)",7 file: fileData,8 options: FileOptions(9 cacheControl: "3600",10 contentType: "image/png",11 upsert: false12 )13 )替换现有文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:update和select
- 请参阅 存储指南,了解访问控制的工作方式
1let fileName = "avatar1.png"23try await supabase.storage4 .from("avatars")5 .update(6 path: "public/\(fileName)",7 file: fileData,8 options: FileOptions(9 cacheControl: "3600",10 contentType: "image/png",11 upsert: true12 )13 )移动现有文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:update和select
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase2 .storage3 .from("avatars")4 .move(from: "public/avatar1.png", to: "private/avatar2.png")复制现有文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:insert和select
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase2 .storage3 .from("avatars")4 .copy(from: "public/avatar1.png", to: "private/avatar2.png")创建签名 URL
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:select
- 请参阅 存储指南,了解访问控制的工作方式
1let signedURL = try await supabase.storage2 .from("avatars")3 .createSignedURL(path: "folder/avatar1.png", expiresIn: 60)创建签名 URL
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:select
- 请参阅 存储指南,了解访问控制的工作方式
1let urls = try await supabase2 .storage3 .from("avatars")4 .createSignedURLs(paths: ["folder/avatar1.png", "folder/avatar2.png"], expiresIn: 60)创建签名上传 URL
创建一个可以用于将文件上传到存储桶的签名上传 URL。
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:insert
- 请参阅 存储指南,了解访问控制的工作方式
1let signedUploadUrl = try await supabase.storage2 .from("avatars")3 .createSignedUploadURL(path: "folder/avatar1.png")上传到签名 URL
使用签名 URL 将文件上传到存储桶。
- 使用使用
createSignedUploadURL()创建的签名上传 URL 上传文件。
1let fileData = "Hello World".data(using: .utf8)!23try await supabase.storage4 .from("avatars")5 .uploadToSignedURL(6 "folder/avatar1.png",7 token: "your-signed-token",8 data: fileData,9 options: FileOptions(10 contentType: "text/plain"11 )12 )检索公共 URL
- 存储桶需要设置为公开,可以通过 updateBucket() 或通过转到 supabase.com/dashboard、单击存储桶上的溢出菜单并选择“公开”来设置。
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:无
- 请参阅 存储指南,了解访问控制的工作方式
1let publicURL = try supabase.storage2 .from("public-bucket")3 .getPublicURL(path: "folder/avatar1.png")下载文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:select
- 请参阅 存储指南,了解访问控制的工作方式
1let data = try await supabase.storage2 .from("avatars")3 .download(path: "folder/avatar1.png")删除存储桶中的文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:delete和select
- 请参阅 存储指南,了解访问控制的工作方式
1try await supabase.storage2 .from("avatars")3 .remove(paths: ["folder/avatar1.png"])列出存储桶中的所有文件
- 所需的 RLS 策略权限
buckets表权限:无objects表权限:select
- 请参阅 存储指南,了解访问控制的工作方式
1let files = try await supabase.storage2 .from("avatars")3 .list(4 path: "folder",5 options: SearchOptions(6 limit: 100,7 offset: 0,8 sortBy: SortBy(column: "name", order: "asc")9 )10 )