Skip to content
Auth

用户会话

Supabase Auth 可以让你对用户的会话进行细致的控制。

🌐 Supabase Auth provides fine-grained control over your user's sessions.

一些对安全敏感的应用,或者需要符合 SOC 2、HIPAA、PCI-DSS 或 ISO27000 的应用,会需要某种额外的会话控制来强制超时或提供额外的安全保障。Supabase Auth 能让构建符合要求的应用变得很简单。

🌐 Some security sensitive applications, or those that need to be SOC 2, HIPAA, PCI-DSS or ISO27000 compliant will require some sort of additional session controls to enforce timeouts or provide additional security guarantees. Supabase Auth makes it easy to build compliant applications.

什么是会话? #

🌐 What is a session?

当用户登录时,会创建一个会话。默认情况下,会话会无限期有效,用户可以在任意数量的设备上拥有无限的活跃会话。

🌐 A session is created when a user signs in. By default, it lasts indefinitely and a user can have an unlimited number of active sessions on as many devices.

一个会话是由 Supabase Auth 访问令牌(JWT 形式)和一个刷新令牌(一个唯一的字符串)表示的。

🌐 A session is represented by the Supabase Auth access token in the form of a JWT, and a refresh token which is a unique string.

访问令牌设计为短期有效,通常在5分钟到1小时之间,而刷新令牌永不过期,但每次只能使用一次。你只能用一次刷新令牌来换取一对新的访问和刷新令牌。

🌐 Access tokens are designed to be short lived, usually between 5 minutes and 1 hour while refresh tokens never expire but can only be used once. You can exchange a refresh token only once to get a new access and refresh token pair.

这个过程叫做刷新会话

🌐 This process is called refreshing the session.

根据配置,会话会在以下情况终止:

🌐 A session terminates, depending on configuration, when:

  • 用户点击退出。
  • 用户更改他们的密码或执行安全敏感操作。
  • 由于长时间不活动,它超时了。
  • 它达到了最大寿命。
  • 用户在另一台设备上登录。

访问令牌(JWT)声明 #

🌐 Access token (JWT) claims

每个访问令牌都包含一个 session_id 声明,这是一个 UUID,用于唯一标识用户会话。你可以将这个 ID 与 auth.sessions 表的主键对应起来。

🌐 Every access token contains a session_id claim, a UUID, uniquely identifying the session of the user. You can correlate this ID with the primary key of the auth.sessions table.

正在开始会话 #

🌐 Initiating a session

当用户登录时,会启动一个会话。会话会存储在 auth.sessions 表中,你的应用应该会收到访问令牌和刷新令牌。

🌐 A session is initiated when a user signs in. The session is stored in the auth.sessions table, and your app should receive the access and refresh tokens.

启动会话并接收令牌有两种方式:

🌐 There are two flows for initiating a session and receiving the tokens:

限制每个用户的会话时长和允许的会话数量 #

🌐 Limiting session lifetime and number of allowed sessions per user

Supabase Auth 可以配置以限制用户会话的有效期。默认情况下,所有会话都会保持活跃,直到用户注销或执行其他会终止会话的操作。

🌐 Supabase Auth can be configured to limit the lifetime of a user's session. By default, all sessions are active until the user signs out or performs some other action that terminates a session.

在一些应用中,为了安全起见,确保用户经常进行身份验证,或者确保会话不会在设备上长时间保持活跃,是很有用或必须的。

🌐 In some applications, it's useful or required for security to ensure that users authenticate often, or that sessions are not left active on devices for too long.

有三种方法可以限制会话的持续时间:

🌐 There are three ways to limit the lifetime of a session:

  • 时间限定的会议,会在规定时间结束。
  • 设置不活动超时,会终止在超时时间内没有刷新过的会话。
  • 每个用户只允许一个会话,只保留最近活跃的那个会话。

为了确保用户需要定期重新认证,你可以在你的项目的认证设置中为 用户会话时限 选项设置一个正值。

🌐 To make sure that users are required to re-authenticate periodically, you can set a positive value for the Time-box user sessions option in the Auth settings for your project.

为了确保会话在一段时间不活动后过期,你可以在认证设置中为不活动超时选项设置一个正数时长。

🌐 To make sure that sessions expire after a period of inactivity, you can set a positive duration for the Inactivity timeout option in the Auth settings.

你也可以限制每个用户在每个设备或浏览器上只能有一个活动会话。启用后,最近一次登录的会话会保持活跃,其余的会被终止。你可以在认证设置中通过“每用户单会话”选项来启用这个功能。

🌐 You can also enforce only one active session per user per device or browser. When this is enabled, the session from the most recent sign in will remain active, while the rest are terminated. Enable this via the Single session per user option in the Auth settings.

更改这些设置时,会话不会被主动销毁,而是在下次刷新会话时才会进行检查。这可能会让开发者感到困惑,因为会话的实际持续时间是配置的超时时间加上 JWT 的过期时间。对于每个用户只有一个会话的情况,效果只有在 JWT 过期时间的间隔才会显现。请根据你的需求调整这个设置。我们不建议把 JWT 过期时间设置低于 5 分钟。

🌐 Sessions are not proactively destroyed when you change these settings, but rather the check is enforced whenever a session is refreshed next. This can confuse developers because the actual duration of a session is the configured timeout plus the JWT expiration time. For single session per user, the effect will only be noticed at intervals of the JWT expiration time. Make sure you adjust this setting depending on your needs. We do not recommend going below 5 minutes for the JWT expiration time.

否则,session 会在过期后 24 小时内逐渐从数据库中删除,这可以防止你不小心给项目造成高负载,同时也让你有一定的自由度来撤销更改,而不会对所有用户产生不良影响。

🌐 Otherwise sessions are progressively deleted from the database 24 hours after they expire, which prevents you from causing a high load on your project by accident and allows you some freedom to undo changes without adversely affecting all users.

常见问题 #

🌐 Frequently asked questions

🌐 What are recommended values for access token (JWT) expiration?

大多数应用应该使用默认的 1 小时过期时间。你可以在 认证设置 > 会话 中自定义这个值。

🌐 Most applications should use the default expiration time of 1 hour. You can customize this value in the Auth settings > Sessions.

出于安全原因,一般不建议将值设置超过 1 小时,但在某些情况下这样做可能是合理的。

🌐 Setting a value over 1 hour is generally discouraged for security reasons, but it may make sense in certain situations.

大多数情况下,不应该使用低于5分钟,尤其是低于2分钟的数值,因为:

🌐 Values below 5 minutes, and especially below 2 minutes, should not be used in most situations because:

  • 过期时间越短,刷新令牌使用得就越频繁,这会增加认证服务器的负担。
  • 时间不是绝对的。服务器的时间经常会有十几秒的偏差,但像注意本、台式机或移动设备这样的用户设备有时可能会差几分钟甚至几个小时。设置过短的过期时间可能会因为时钟偏差而导致难以调试的错误。
  • Supabase 的客户端库总是会尝试提前刷新会话,如果过期时间太短的话,这是不可能的。
  • 访问令牌通常应该至少保持有效,直到你应用中最长的请求完成为止。这可以帮助你避免在处理过程中令牌失效的问题。

什么是刷新令牌重复使用检测,它能防护什么? #

🌐 What is refresh token reuse detection and what does it protect from?

随着你的用户不断使用你的应用,刷新令牌会不断被换成新的访问令牌。

🌐 As your users continue using your app, refresh tokens are being constantly exchanged for new access tokens.

一般规则是刷新令牌只能使用一次。不过,严格执行这一规则可能会引发一些问题。为了防止用户会话过早或意外终止,这一设计有两个例外:

🌐 The general rule is that a refresh token can only be used once. However, strictly enforcing this can cause certain issues to arise. There are two exceptions to this design to prevent the early and unexpected termination of user's sessions:

  • 刷新令牌可以在定义的重用间隔内多次使用。默认情况下,这个间隔是10秒,我们不建议更改这个值。这样的例外情况是为了合法的情况,例如:
    • 在使用服务器端渲染时,需要在服务器上重复使用同一个刷新令牌,然后很快在客户端也使用它
    • 为了给刷新令牌请求的序列化访问留出一些余地,以防出现漏洞或问题
  • 如果正在使用用户会话的当前活动刷新令牌的父令牌,将返回活动令牌。这个异常解决了一个重要且常见的情况:
    • 所有客户端,比如浏览器、移动或桌面应用,甚至一些服务器,由于网络问题本身就不可靠。一次请求并不意味着它们收到了响应,或者甚至处理了收到的响应。
    • 如果刷新令牌在只使用一次后就被撤销,而客户端没有收到或处理响应,当客户端重新上线时,它会尝试使用已经使用过的刷新令牌。由于这可能发生在重用间隔之外,这可能会导致会话突然和意外地终止。

如果重用尝试不属于这两种例外情况,整个会话将被视为已终止,属于该会话的所有刷新令牌都将被标记为已撤销。你可以在 Auth 设置 页面的高级设置中禁用此行为,不过通常不建议这样做。

🌐 Should the reuse attempt not fall under these two exceptions, the whole session is regarded as terminated and all refresh tokens belonging to it are marked as revoked. You can disable this behavior in the Advanced Settings of the Auth settings page, though it is generally not recommended.

这个机制的目的是防止潜在的安全问题,比如刷新令牌被盗,比如意外暴露在泄露的日志中(比如记录了 cookie、请求体或 URL 参数)或者通过有漏洞的第三方服务器。它并不能防护用户在设备上被盗用会话的情况。

🌐 The purpose of this mechanism is to guard against potential security issues where a refresh token could have been stolen from the user, for example by exposing it accidentally in logs that leak (like logging cookies, request bodies or URL params) or via vulnerable third-party servers. It does not guard against the case where a user's session is stolen from their device.

使用访问令牌和刷新令牌而不是传统会话有什么好处? #

🌐 What are the benefits of using access and refresh tokens instead of traditional sessions?

传统上,用户会话是通过在 Cookie 中存储一个唯一字符串来实现的,这个字符串用于识别用户在特定浏览器上的授权。应用会使用这个唯一字符串在每次 API 调用时不断获取附加的用户信息。

🌐 Traditionally user sessions were implemented by using a unique string stored in cookies that identified the authorization that the user had on a specific browser. Applications would use this unique string to constantly fetch the attached user information on every API call.

与使用基于 JWT 的方法相比,这种方法有一些权衡:

🌐 This approach has some tradeoffs compared to using a JWT-based approach:

  • 如果认证服务器或它的数据库崩溃,或者哪怕只有几秒钟无法使用,整个应用就会瘫痪。安排维护或者应对临时错误就会变得非常棘手。
  • 一个认证服务器出问题可能会引发其他系统和 API 的连锁故障,让整个应用系统瘫痪。
  • 所有需要身份验证的请求都必须通过身份验证路由,这会给所有请求增加额外的延迟。

Supabase Auth 更倾向于使用基于 JWT 的方法,通过访问令牌和刷新令牌来实现,因为会话信息被编码在短期有效的访问令牌中,这样就能在不同的 API 和系统之间传递,而不依赖中央服务器的可用性或性能。这种方式提高了应用对临时故障或性能问题的容忍度。此外,主动刷新访问令牌还能让应用在重大故障期间仍能可靠运行。

🌐 Supabase Auth prefers a JWT-based approach using access and refresh tokens because session information is encoded within the short-lived access token, enabling transfer across APIs and systems without dependence on a central server's availability or performance. This approach enhances an application's tolerance to transient failures or performance issues. Furthermore, proactively refreshing the access token allows the application to function reliably even during significant outages.

这对成本优化和扩展也更好,因为认证系统的服务器和数据库只处理这个用例的流量。

🌐 It's better for cost optimization and scaling as well, as the authentication system's servers and database only handle traffic for this use case.

如何确保用户登出后访问令牌(JWT)不能再被使用 #

🌐 How to ensure an access token (JWT) cannot be used after a user signs out

大多数应用很少需要这么强的保障。可以考虑将 JWT 的过期时间调整到一个可接受的值。如果仍然有必要,你应该尽量只在应用中最敏感的操作上使用这种验证逻辑。

🌐 Most applications rarely need such strong guarantees. Consider adjusting the JWT expiry time to an acceptable value. If this is still necessary, you should try to use this validation logic only for the most sensitive actions within your application.

当用户登出时,受登出影响的会话会从数据库中完全移除。你可以检查 JWT 中的 session_id 声明是否对应 auth.sessions 表中的一行。如果不存在这样的行,说明用户已经登出。

🌐 When a user signs out, the sessions affected by the logout are removed from the database entirely. You can check that the session_id claim in the JWT corresponds to a row in the auth.sessions table. If such a row does not exist, it means that the user has logged out.

注意,当会话达到最大生命周期(时间限制)或不活跃超时后,并不会被主动终止。这些会话会在达到该状态后24小时内逐步清理。这让你可以调整数值或撤销更改,而不会引起用户不必要的麻烦。

🌐 Note that sessions are not proactively terminated when their maximum lifetime (time-box) or inactivity timeout are reached. These sessions are cleaned up progressively 24 hours after reaching that status. This allows you to tweak the values or roll back changes without causing unintended user friction.

使用仅限 HTTP 的 Cookie 来存储访问令牌和刷新令牌 #

🌐 Using HTTP-only cookies to store access and refresh tokens

这是可能的,但仅适用于那些使用传统的仅服务器端 Web 应用方法的应用,这种方法的所有应用逻辑都在服务器上实现,并且只返回渲染后的 HTML。

🌐 This is possible, but only for apps that use the traditional server-only web app approach where all of the application logic is implemented on the server and it returns rendered HTML only.

如果你的应用使用任何客户端 JavaScript 来构建丰富的用户体验,那么使用仅 HTTP 的 Cookies 就不太可行,因为只有你的服务器才能读取和刷新用户的会话。浏览器将无法访问访问令牌和刷新令牌。

🌐 If your app uses any client side JavaScript to build a rich user experience, using HTTP-Only cookies is not feasible since only your server will be able to read and refresh the session of the user. The browser will not have access to the access and refresh tokens.

因此,Supabase 的 JavaScript 库只提供有限的支持。你可以在 服务器端 创建 Supabase 客户端时覆盖 storage 选项,将值存储在 cookies 或你喜欢的存储方式中,例如:

🌐 Because of this, the Supabase JavaScript libraries provide only limited support. You can override the storage option when creating the Supabase client on the server to store the values in cookies or your preferred storage choice, for example:

1
import { createClient } from '@supabase/supabase-js'
2
3
const supabase = createClient('SUPABASE_URL', 'SUPABASE_PUBLISHABLE_KEY', {
4
auth: {
5
storage: {
6
getItem: () => {
7
return Promise.resolve('FETCHED_COOKIE')
8
},
9
setItem: () => {},
10
removeItem: () => {},
11
},
12
},
13
})

customStorageObject 应该实现 Storage 接口 中的 getItemsetItemremoveItem 方法。这些方法的异步版本也支持。

🌐 The customStorageObject should implement the getItem, setItem, and removeItem methods from the Storage interface. Async versions of these methods are also supported.

在使用 cookies 存储访问令牌和刷新令牌时,确保 cookies 的 ExpiresMax-Age 属性 设置为很远未来的时间戳。浏览器会清除 cookies,但 Supabase Auth 中的会话仍然会保持活动状态。因此,最好让 Supabase Auth 控制这些令牌的有效期,并告诉浏览器始终无限期地存储 cookies。

🌐 When using cookies to store access and refresh tokens, make sure that the Expires or Max-Age attributes of the cookies is set to a timestamp very far into the future. Browsers will clear the cookies, but the session will remain active in Supabase Auth. Therefore it's best to let Supabase Auth control the validity of these tokens and instruct the browser to always store the cookies indefinitely.