Swift 参考 v2.0

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、AuthRealtimeStoragePostgREST

1
let 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 Storage
16
package: "supabase-swift"
17
),
18
]
19
)
20
]
21
)

初始化

您可以使用 SupabaseClient 通过传递您的 项目 URL项目密钥 来初始化 Supabase。您可以在 项目设置API 设置 中找到这些信息。Supabase 客户端是您进入 Supabase 所有功能的入口点,也是与我们 Supabase 生态系统中的所有内容交互的最简单方法。

1
import Supabase
2
3
let client = SupabaseClient(supabaseURL: URL(string: "https://xyzcompany.supabase.co")!, supabaseKey: "publishable-or-anon-key")

获取数据

  • 默认情况下,Supabase 项目将返回最多 1,000 行。 可以在项目 API 设置中更改此设置。 建议将其保持较低,以限制意外或恶意请求的有效负载大小。 您可以使用 range() 查询来分页您的数据。
  • select() 可以与 修饰符 结合使用
  • select() 可以与 过滤器 结合使用
  • 如果使用 Supabase 托管平台,apikey 在技术上是一个保留关键字,因为 API 网关会将其提取出来用于身份验证。 应避免将其用作列名
  • 获取数据的推荐方法是使用 value 属性,它将返回解码后的模型。创建一个 Codable 以轻松解码您的数据库响应。
1
struct Instrument: Decodable {
2
let id: Int
3
let name: String
4
}
5
6
let instruments: [Instrument] = try await supabase
7
.from("instruments")
8
.select()
9
.execute()
10
.value

插入数据

1
struct Instrument: Encodable {
2
let id: Int
3
let name: String
4
}
5
6
let instrument = Instrument(id: 1, name: "ukelele")
7
8
try await supabase
9
.from("instruments")
10
.insert(instrument)
11
.execute()

更新数据

  • update() 始终应与 过滤器 结合使用,以定位您希望更新的项目。
1
try await supabase
2
.from("instruments")
3
.update(["name": "piano"])
4
.eq("id", value: 1)
5
.execute()

更新或插入数据

  • 要使用 upsert,必须在 values 中包含主键。
1
struct Instrument: Encodable {
2
let id: Int
3
let name: String
4
}
5
try await supabase
6
.from("instruments")
7
.upsert(Instrument(id: 1, name: "piano"))
8
.execute()

删除数据

  • delete() 始终应与 过滤器 结合使用,以定位您希望删除的项目。
  • 如果您使用带有过滤器的 delete() 并且启用了 RLS,则只会删除通过 SELECT 策略可见的行。请注意,默认情况下没有行可见,因此您至少需要一个使行可见的 SELECT/ALL 策略。
1
try await supabase
2
.from("instruments")
3
.delete()
4
.eq("id", value: 1)
5
.execute()

调用 Postgres 函数

您可以将 Postgres 函数作为远程过程调用来调用,这些是在您的数据库中可以从任何地方执行的逻辑。当逻辑很少更改时,函数很有用——例如用于密码重置和更新。

1
create or replace function hello_world() returns text as $$
2
select 'Hello world';
3
$$ language sql;
1
let value: String = try await supabase
2
.rpc("hello_world")
3
.execute()
4
.value

使用过滤器

过滤器允许你仅返回匹配特定条件的行。

过滤器可用于 select()update()upsert()delete() 查询。

如果 Postgres 函数返回表响应,您也可以应用过滤器。

在您自己的类型中实现 URLQueryRepresentable 协议,以便能够将其用作过滤器值。

支持的过滤器是:eqneqgtgteltltelikeilikeisincscdslsrnxlnxradjovftsplftsphftswfts。请在 PostgREST 中查看可用的运算符。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.eq("name", value: "The Shire") // Correct
5
6
try await supabase
7
.from("citites")
8
.eq("name", value: "The Shire") // Incorrect
9
.select("name, country_id")

列等于一个值

仅匹配 column 等于 value 的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.eq("name", value: "The shire")

列不等于一个值

仅匹配 column 不等于 value 的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.neq("name", value: "Paris")

列大于一个值

仅匹配 column 大于 value 的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.gt("country_id", value: 250)

列大于或等于一个值

仅匹配 column 大于或等于 value 的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.gte("country_id", value: 250)

列小于一个值

仅匹配 column 小于 value 的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.lt("country_id", value: 250)

列小于或等于一个值

仅匹配 column 小于或等于 value 的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.lte("country_id", value: 250)

列匹配一个模式

仅匹配 columnpattern 区分大小写匹配的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.like("name", pattern: "%la%")

列匹配一个不区分大小写的模式

仅匹配 columnpattern 不区分大小写匹配的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.ilike("name", pattern: "%la%")

列是一个值

仅匹配 column IS value 的行。对于非空值,这等同于 eq 过滤器。对于空值,请使用此过滤器代替 eq

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.is("name", value: nil)

列在一个数组中

仅匹配 column 包含在 values 数组中的行。

1
try await supabase
2
.from("cities")
3
.select("name, country_id")
4
.in("name", values: ["Rio de Janeiro", "San Francisco"])

列包含数组中的每个元素

仅匹配 column 包含 value 中出现的每个元素的行。

1
try await supabase
2
.from("cities")
3
.select("name, main_exports")
4
.contains("main_exports", value: ["oil"])

具有共同元素

仅匹配 columnvalue 具有共同元素的行。

1
try await supabase
2
.from("cities")
3
.select("name, main_exports")
4
.overlaps("main_exports", value: ["exports", "tourism"])

匹配关联值

1
try await supabase
2
.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.
1
try await supabase
2
.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()`
1
try await supabase
2
.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` filter
2
.filter("arraycol", operator: "cs", value: #"{"a","b"}"#) // Use `cs` for `contains()`, `{}` for array values
1
try await supabase
2
.from("instruments")
3
.select()
4
.filter("name", operator: "in", value: #"("cello","guzheng")"#)

使用修饰符

过滤器在行级别起作用——它们允许您仅返回匹配特定条件的行,而不会更改行的形状。修饰符是所有不符合该定义的内容——允许您更改响应的格式(例如,返回 CSV 字符串)。

修饰符必须在过滤器之后指定。某些修饰符仅适用于返回行的查询(例如,select() 或返回表响应的函数的 rpc())。


插入后返回数据

对查询结果执行 SELECT。

1
try await supabase
2
.from("instruments")
3
.upsert(InstrumentModel(id: 1, name: "piano"))
4
.select()
5
.execute()

对结果进行排序

按列对查询结果进行排序。

1
try await supabase
2
.from("instruments")
3
.select("id, name")
4
.order("id", ascending: false)
5
.execute()

限制返回的行数

按计数限制查询结果。

1
try await supabase
2
.from("instruments")
3
.select("id, name")
4
.limit(1)
5
.execute()

将查询限制在一个范围内

按 from 和 to 包含性地限制查询结果。

1
try await supabase
2
.from("instruments")
3
.select("name")
4
.range(from: 0, to: 1)
5
.execute()

检索一行数据

默认情况下,PostgREST 将所有 JSON 结果返回到一个数组中,即使只有一个项目,也请使用 single() 将第一个对象返回而不包含在数组中。

1
try await supabase
2
.from("instruments")
3
.select("name")
4
.limit(1)
5
.single()
6
.execute()

检索为 CSV

1
try await supabase
2
.from("instruments")
3
.select()
4
.csv()
5
.execute()

使用 explain

为了调试慢查询,你可以使用 explain() 方法获取查询的 Postgres EXPLAIN 执行计划。这适用于任何查询,甚至适用于 rpc() 或写入。

Explain 默认情况下未启用,因为它可能会泄露数据库中的敏感信息。最好仅在测试环境中使用,但如果您希望在生产环境中使用,可以通过使用 `pre-request` 函数提供额外的保护。

请遵循 性能调试指南 以在您的项目上启用此功能。

1
try await supabase
2
.from("instruments")
3
.select()
4
.explain()
5
.execute()
6
.value

概述

可以通过 supabase.auth 命名空间访问身份验证方法。

UIKit 应用生命周期#

1
public 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
}
8
9
return true
10
}
11
12
func application(
13
_ app: UIApplication,
14
open url: URL,
15
options: [UIApplication.OpenURLOptionsKey: Any]
16
) -> Bool {
17
supabase.auth.handle(url)
18
return true
19
}
20
21
#### UIKit app lifecycle with scenes
22
23
In your `SceneDelegate.swift`:
24
25
```swift
26
func 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

1
SomeView()
2
.onOpenURL { url in
3
supabase.auth.handle(url)
4
}
1
let supabase = SupabaseClient(supabaseURL: URL(string: "https://xyzcompany.supabase.co")!, supabaseKey: "publishable-or-anon-key")
2
let auth = supabase.auth

创建新用户

  • 默认情况下,用户需要在登录前验证其电子邮件地址。要关闭此功能,请在 您的项目中 禁用 确认电子邮件
  • **确认电子邮件** 确定用户在注册后是否需要确认其电子邮件地址。
    • 如果启用了 **确认电子邮件**,则会返回一个 `user`,但 `session` 为 null。
    • 如果禁用了 **确认电子邮件**,则会同时返回 `user` 和 `session`。
  • 当用户确认其电子邮件地址时,默认情况下他们将被重定向到 SITE_URL。您可以在 您的项目 中修改您的 SITE_URL 或添加其他重定向 URL。
  • 如果对已存在的已确认用户调用 signUp()
    • 当在 您的项目 中同时启用 **确认电子邮件** 和 **确认电话**(即使电话提供程序已禁用)时,将返回一个混淆/虚假的用户对象。
    • 当 **确认电子邮件** 或 **确认电话**(即使电话提供程序已禁用)中的任何一个被禁用时,将返回错误消息 `User already registered`。
  • 要获取当前登录的用户,请参阅 getUser()

参数

  • email
    可选
    字符串

    必须提供 emailphone 中的一个。

  • phone
    可选
    字符串

    必须提供 emailphone 中的一个。

  • passwordString
  • data
    可选
    JSONObject

    一个自定义数据对象,用于存储其他用户元数据。

  • redirectTo
    可选
    URL

    仅用于电子邮件注册。嵌入在电子邮件链接中的重定向 URL。必须是您 Supabase 实例配置的重定向 URL。

  • captchaToken
    可选
    字符串
1
try 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,用户可以在其中 重置他们的密码
1
// Using AsyncStream
2
for await (event, session) in await supabase.auth.authStateChanges {
3
print(event, session)
4
}
5
6
// Using Closure
7
let subscription = await supabase.auth.onAuthStateChange { event, session in
8
print(event, session)
9
}
10
11
// call remove() to remove subscription
12
subscription.remove()

创建匿名用户

  • 返回一个匿名用户
  • 建议为匿名注册设置验证码以防止滥用。您可以在 `options` 参数中传递验证码令牌。
1
let session = try await supabase.auth.signInAnonymously(captchaToken: captchaToken)

登录用户

  • 需要电子邮件和密码或电话号码和密码。

参数

  • email
    可选
    字符串

    必须提供 emailphone 中的一个。

  • phone
    可选
    字符串

    必须提供 emailphone 中的一个。

  • passwordString
  • captchaToken
    可选
    字符串
1
try await supabase.auth.signIn(
2
email: "example@email.com",
3
password: "example-password"
4
)

使用 ID Token 登录 (原生登录)

1
let 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
    可选
    字符串

    必须提供 emailphone 中的一个。

  • phone
    可选
    字符串

    必须提供 emailphone 中的一个。

  • redirectTo
    可选
    字符串

    仅用于电子邮件注册。嵌入在电子邮件链接中的重定向 URL。必须是您 Supabase 实例配置的重定向 URL。

  • channel
    可选
    MessagingChannel

    用于发送消息的通道。仅用于电话注册。

  • shouldCreateUser
    可选
    布尔值

    如果用户不存在,是否创建用户。默认为 true。

  • data
    可选
    JSONObject

    一个自定义数据对象,用于存储其他用户元数据。

  • captchaToken
    可选
    字符串
1
try 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 流程的自定义配置回调函数。

1
let session = try await supabase.auth.signInWithOAuth(
2
provider: .github
3
) { (session: ASWebAuthenticationSession) in
4
// customize session
5
}

通过 SSO 登录用户

  • 在您可以使用此方法之前,您需要 建立与身份提供程序的连接。使用 CLI 命令 来执行此操作。
  • 如果您已将电子邮件域与身份提供程序关联,则可以使用 `domain` 属性启动登录流程。
  • 如果您需要使用不同的方式使用身份提供程序启动身份验证流程,可以使用 `providerId` 属性。例如
    • 将特定的用户电子邮件地址与身份提供程序映射。
    • 使用不同的提示来识别用户要使用的身份提供程序,例如公司特定的页面、IP 地址或其他跟踪信息。

参数

  • providerId
    可选
    字符串

    SSO 提供商的 UUID。providerIddomain 之一是必需的。

  • domain
    可选
    字符串

    使用 SSO 的组织的域名。providerIddomain 之一是必需的。

  • redirectTo字符串

    用户登录后要重定向到的 URL。必须是您 Supabase 实例配置的重定向 URL。

  • captchaToken字符串
1
// You can extract the user's email domain and use it to trigger the
2
// authentication flow with the correct identity provider.
3
4
let url = try await await supabase.auth.signInWithSSO{
5
domain: "company.com"
6
}
7
8
// 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。

1
let response = try await supabase.auth.getClaims()
2
print("User ID: \(response.claims.sub ?? "N/A")")
3
print("Email: \(response.claims.email ?? "N/A")")
4
print("Role: \(response.claims.role ?? "N/A")")

注销用户

  • 为了使用 `signOut()` 方法,用户需要先登录。
1
try await supabase.auth.signOut()

通过 OTP 验证并登录

  • verifyOTP 方法接受不同类型的验证。如果使用电话号码,则类型可以是 smsphone_change。如果使用电子邮件地址,则类型可以是以下之一:signupmagiclinkrecoveryinviteemail_changeemail
  • 应根据在调用 verifyOTP 注册/登录用户之前调用的相应身份验证方法来确定使用的验证类型。

参数

  • email
    可选
    字符串

    必须提供 phoneemailtoken_hash 之一。

  • phone
    可选
    字符串

    必须提供 phoneemailtoken_hash 之一。

  • token_hash
    可选
    字符串

    用户电子邮件链接中的令牌哈希。必须提供 phoneemailtoken_hash 之一。

  • typeEmailOTPType | MobileOTPType
  • token
    可选
    字符串

    发送给用户的 OTP。如果使用 phoneemail,则需要。

  • redirectTo
    可选
    URL

    用户确认后要重定向到的 URL。必须在您配置的重定向 URL 中。

  • captchaToken
    可选
    字符串

    已弃用。

1
try await supabase.auth.verifyOTP(
2
phone: "+13334445555",
3
token: "123456",
4
type: .sms
5
)

获取会话

  • 返回会话,如果需要则刷新它。如果找不到会话,则会抛出 GoTrueError.sessionNotFound 错误。
1
try await supabase.auth.session

获取新的会话

  • 此方法将刷新会话,无论当前会话是否过期。
1
let session = try await supabase.auth.refreshSession()

获取用户

  • 此方法对于检查用户是否已授权很有用,因为它会在服务器上验证用户的访问令牌 JWT。
  • 从数据库而不是本地会话中获取用户对象。
  • 仅当您需要最新的用户数据时才应使用此方法。为了获得更快的速度,建议使用 session.user
1
let user = try await supabase.auth.user()

更新用户

  • 为了使用 `updateUser()` 方法,用户需要先登录。
  • 默认情况下,电子邮件更新会将确认链接发送到用户的当前电子邮件和新电子邮件。要仅将确认链接发送到用户的新的电子邮件,请在您项目的 电子邮件身份验证提供程序设置 中禁用 **安全电子邮件更改**。
1
try await supabase.auth.update(user: UserAttributes(email: "new@email.com"))

获取与用户关联的身份

  • 需要用户登录才能调用 userIdentities()
1
let identities = try await supabase.auth.userIdentities()

将身份与用户关联

  • 必须从您的 项目身份验证设置 中启用 **启用手动链接** 选项。
  • 需要先登录才能调用 `linkIdentity()`。
  • 如果候选身份已链接到现有用户或另一个用户,`linkIdentity()` 将失败。

将身份从用户取消关联

  • 必须从您的 项目身份验证设置 中启用 **启用手动链接** 选项。
  • 用户需要已登录才能调用 unlinkIdentity()
  • 用户必须至少拥有 2 个身份才能取消关联一个身份。
  • 要取消关联的身份必须属于该用户。

发送密码重新认证 nonce

  • 当需要更新用户的密码时,此方法与 update(user:) 一起使用。
  • 如果您要求用户在更新密码之前重新进行身份验证,则需要在您的 项目电子邮件提供程序设置中启用 安全密码更改 选项。
  • 如果启用了安全密码更改并且用户最近未登录,则用户只需要在更新密码之前重新进行身份验证。如果会话在过去 24 小时内创建,则认为用户最近已登录。
  • 此方法会将 nonce 发送到用户的电子邮件。如果用户没有确认的电子邮件地址,该方法会将 nonce 发送到用户的确认的电话号码。
1
try await supabase.auth.reauthenticate()

重新发送 OTP

  • 重新发送注册确认、电子邮件更改或电话号码更改电子邮件给用户。
  • 可以通过再次调用 signInWithOTP() 方法重新发送无密码登录。
  • 可以通过再次调用 resetPasswordForEmail() 方法重新发送密码恢复电子邮件。
  • 只有在进行了初始注册、电子邮件更改或电话号码更改请求后,此方法才会重新发送电子邮件或电话 OTP 给用户。
  • 您可以使用 emailRedirectTo 选项在重新发送电子邮件链接时指定重定向 URL。
1
try 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,它提供了一个简短的时间窗口,在此期间可以在并发或离线问题的情况下多次使用相同的刷新令牌。
1
try await supabase.auth.setSession(accessToken: "access_token", refreshToken: "refresh_token")

将授权码交换为会话

  • 当客户端选项中的 flowType 设置为 pkce 时使用。
1
try await supabase.auth.exchangeCodeForSession(authCode: "34e770dd-9ff9-416c-87fa-43b31d7ef225")

启动自动刷新会话(非浏览器)

启动自动会话刷新过程。

1
supabase.auth.startAutoRefresh()

停止自动刷新会话(非浏览器)

停止自动会话刷新过程。

1
supabase.auth.stopAutoRefresh()

认证 MFA

本节包含通常用于多因素身份验证 (MFA) 的方法,并在 supabase.auth.mfa 命名空间下调用。

目前,我们仅支持基于时间的 One-Time Password (TOTP) 作为第二个因素。我们不支持恢复代码,但允许用户注册超过 1 个 TOTP 因素,上限为 10 个。

拥有第二个 TOTP 因素用于恢复,可以减轻用户存储恢复代码的负担。它还可以减少攻击面,因为通常会生成多个恢复代码,而不仅仅是 1 个备份 TOTP 因素。


注册因素

1
let response = try await supabase.auth.mfa.enroll(
2
params: MFAEnrollParams(
3
issuer: "optional issuer",
4
friendlyName: "optional friendly name"
5
)
6
)
7
8
// 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.
11
let id = response.id
12
let type = response.type
13
let qrCode = response.totp?.qrCode
14
let secret = response.totp?.secret
15
let uri = response.totp?.uri

创建挑战

1
let response = try await supabase.auth.mfa.challenge(
2
params: MFAChallengeParams(
3
factorId: "34e770dd-9ff9-416c-87fa-43b31d7ef225"
4
)
5
)

验证挑战

1
let 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
)

创建并验证挑战

1
let 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
1
let response = try await supabase.auth.mfa.unenroll(
2
params: MFAUnenrollParams(
3
factorId: "34e770dd-9ff9-416c-87fa-43b31d7ef225"
4
)
5
)
6
print(response.id) // ID of the unenrolled factor

获取身份验证器保证级别

  • 身份验证器保证级别 (AAL) 是身份验证机制强度的度量。
  • 在 Supabase 中,具有 aal1 的 AAL 指的是第一因素身份验证,例如电子邮件和密码或 OAuth 登录,而 aal2 指的是第二因素身份验证,例如基于时间的一次性密码 (TOTP)。
  • 如果用户具有经过验证的因素,则 nextLevel 字段将返回 aal2,否则,将返回 aal1
1
let aal = try await supabase.auth.mfa.getAuthenticatorAssuranceLevel()
2
let currentLevel = aal.currentLevel
3
let nextLevel = aal.nextLevel
4
let currentAuthenticationMethods = aal.currentAuthenticationMethods

认证 Admin

  • supabase.auth.admin 命名空间下的任何方法都需要一个 service_role 密钥。
  • 这些方法被认为是管理方法,应在受信任的服务器上调用。切勿在浏览器中公开你的 service_role 密钥。
1
import Supabase
2
3
let supabase = SupabaseClient(
4
supabaseURL: supabaseURL,
5
supabaseKey: serviceRoleKey
6
)
7
8
// Access auth admin api
9
let adminAuthClient = supabase.auth.admin

获取用户

按 ID 获取用户。

  • getUserById() 方法需要用户的 ID。
1
let user = try await supabase.auth.admin.getUserById(
2
"715ed5db-f090-4b8c-a067-640ecee36aa0"
3
)

列出所有用户

列出系统中的所有用户。

1
let users = try await supabase.auth.admin.listUsers()

创建用户

创建一个新用户。

1
let user = try await supabase.auth.admin.createUser(
2
attributes: AdminUserAttributes(
3
email: "user@email.com",
4
password: "password",
5
emailConfirm: true
6
)
7
)

删除用户

  • deleteUser() 方法需要用户的 ID,它映射到 auth.users.id 列。
1
try await supabase.auth.admin.deleteUser(
2
id: "715ed5db-f090-4b8c-a067-640ecee36aa0"
3
)

发送电子邮件邀请链接

向用户的电子邮件地址发送邀请链接。

1
let 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 更新用户。

1
let 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 标头。
  • 当您传递一个主体给您的函数时,我们自动为 StringData 附加 Content-Type 标头。如果它不匹配任何这些类型,我们假定有效负载是 json,对其进行序列化并将 Content-Type 标头附加为 application/json。您可以通过传递自己的 Content-Type 标头来覆盖此行为。
  • 当指定区域时,将设置 x-region 标头和 forceFunctionRegion 查询参数,以确保正确的函数路由。
1
struct Response: Decodable {
2
// Expected response definition
3
}
4
5
let response: Response = try await supabase.functions
6
.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 或回调来监听更改。
1
let channel = supabase.channel("room1")
2
3
let broadcastStream = channel.broadcastStream(event: "cursor-pos")
4
5
await channel.subscribe()
6
7
Task {
8
for await message in broadcastStream {
9
print("Cursor position received", message)
10
}
11
}
12
13
await 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 来禁用。
1
let channel = supabase.channel("channelId")
2
3
//...
4
await supabase.removeChannel(channel)

取消订阅所有频道

取消订阅并从实时客户端删除所有实时通道。

  • 删除频道是维护项目实时服务性能以及数据库性能的好方法(如果你正在侦听 Postgres 更改)。Supabase 会在客户端断开连接 30 秒后自动处理清理,但未使用的频道可能会导致更多客户端同时订阅而导致性能下降。
  • 如果您删除了所有通道,客户端将自动断开实时 websocket 连接。这可以在实时配置中通过将 disconnectOnNoSubscriptions 设置为 false 来禁用。
1
await supabase.removeAllChannels()

获取所有频道

返回所有实时通道。

1
let channels = supabase.channels

文件存储

本节包含处理文件存储桶的方法。


列出所有存储桶

  • 所需的 RLS 策略权限
    • buckets 表权限:select
    • objects 表权限:无
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase.storage
2
.listBuckets()

检索存储桶

  • 所需的 RLS 策略权限
    • buckets 表权限:select
    • objects 表权限:无
  • 请参阅 存储指南,了解访问控制的工作方式
1
let bucket = try await supabase.storage
2
.getBucket("avatars")

创建存储桶

  • 所需的 RLS 策略权限
    • buckets 表权限:insert
    • objects 表权限:无
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase.storage
2
.createBucket(
3
"avatars",
4
options: BucketOptions(
5
public: false,
6
allowedMimeTypes: ["image/png"],
7
fileSizeLimit: 1024
8
)
9
)

清空存储桶

  • 所需的 RLS 策略权限
    • buckets 表权限:select
    • objects 表权限:selectdelete
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase.storage
2
.emptyBucket("avatars")

更新存储桶

  • 所需的 RLS 策略权限
    • buckets 表权限:selectupdate
    • objects 表权限:无
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase.storage
2
.updateBucket(
3
"avatars",
4
options: BucketOptions(
5
public: false,
6
fileSizeLimit: 1024,
7
allowedMimeTypes: ["image/png"]
8
)
9
)

删除存储桶

  • 所需的 RLS 策略权限
    • buckets 表权限:selectdelete
    • objects 表权限:无
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase.storage
2
.deleteBucket("avatars")

上传文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:仅当上传新文件时为 insert,当更新文件时为 selectinsertupdate
  • 请参阅 存储指南,了解访问控制的工作方式
1
let fileName = "avatar1.png"
2
3
try await supabase.storage
4
.from("avatars")
5
.upload(
6
path: "public/\(fileName)",
7
file: fileData,
8
options: FileOptions(
9
cacheControl: "3600",
10
contentType: "image/png",
11
upsert: false
12
)
13
)

替换现有文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:updateselect
  • 请参阅 存储指南,了解访问控制的工作方式
1
let fileName = "avatar1.png"
2
3
try await supabase.storage
4
.from("avatars")
5
.update(
6
path: "public/\(fileName)",
7
file: fileData,
8
options: FileOptions(
9
cacheControl: "3600",
10
contentType: "image/png",
11
upsert: true
12
)
13
)

移动现有文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:updateselect
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase
2
.storage
3
.from("avatars")
4
.move(from: "public/avatar1.png", to: "private/avatar2.png")

复制现有文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:insertselect
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase
2
.storage
3
.from("avatars")
4
.copy(from: "public/avatar1.png", to: "private/avatar2.png")

创建签名 URL

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:select
  • 请参阅 存储指南,了解访问控制的工作方式
1
let signedURL = try await supabase.storage
2
.from("avatars")
3
.createSignedURL(path: "folder/avatar1.png", expiresIn: 60)

创建签名 URL

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:select
  • 请参阅 存储指南,了解访问控制的工作方式
1
let urls = try await supabase
2
.storage
3
.from("avatars")
4
.createSignedURLs(paths: ["folder/avatar1.png", "folder/avatar2.png"], expiresIn: 60)

创建签名上传 URL

创建一个可以用于将文件上传到存储桶的签名上传 URL。

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:insert
  • 请参阅 存储指南,了解访问控制的工作方式
1
let signedUploadUrl = try await supabase.storage
2
.from("avatars")
3
.createSignedUploadURL(path: "folder/avatar1.png")

上传到签名 URL

使用签名 URL 将文件上传到存储桶。

  • 使用使用 createSignedUploadURL() 创建的签名上传 URL 上传文件。
1
let fileData = "Hello World".data(using: .utf8)!
2
3
try await supabase.storage
4
.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 表权限:无
  • 请参阅 存储指南,了解访问控制的工作方式
1
let publicURL = try supabase.storage
2
.from("public-bucket")
3
.getPublicURL(path: "folder/avatar1.png")

下载文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:select
  • 请参阅 存储指南,了解访问控制的工作方式
1
let data = try await supabase.storage
2
.from("avatars")
3
.download(path: "folder/avatar1.png")

删除存储桶中的文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:deleteselect
  • 请参阅 存储指南,了解访问控制的工作方式
1
try await supabase.storage
2
.from("avatars")
3
.remove(paths: ["folder/avatar1.png"])

列出存储桶中的所有文件

  • 所需的 RLS 策略权限
    • buckets 表权限:无
    • objects 表权限:select
  • 请参阅 存储指南,了解访问控制的工作方式
1
let files = try await supabase.storage
2
.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
)