# 用户认证（Authentication）
#### 场景介绍
任何面向最终用户的商用应用或服务，都绕不开"谁在用我的应用"这一问题：要区分用户身份、归属数据、控制可见内容、记录操作来源。用户认证（Authentication）正是解决此问题的模块，负责注册、登录、会话维持与注销，为每位用户分配唯一身份并在后续请求中持续验证。如同门禁先识别访客才放行，应用也须先识别用户，才能放行后续操作。
传统做法通常需要客户自行研发，包括建立用户表、编写密码加密与校验逻辑、实现令牌签发与会话刷新功能、找回密码机制以及第三方对接等，同时还需兼顾防撞库、防重放、防注入与安全合规要求，导致研发与运维成本较高。
华为云RDS Supabase的认证模块开箱即用，其核心作用是帮助开发者快速、安全地完成用户注册、登录及权限控制，无需从零构建复杂的安全底座，可显著缩短研发周期；密码哈希、会话安全、防暴力破解等安全机制均由平台托管，符合现代网络安全标准，有效降低自建账号系统漏洞导致的数据泄露风险。
模块提供邮箱密码与GitHub单点登录（SSO）两种方式，覆盖常见登录场景；自动处理访问令牌（Access Token）与刷新令牌（Refresh Token）的生成、分发与刷新，维持安全的登录状态；并与行级安全（RLS）深度整合。登录后自动获得authenticated身份，可按当前登录用户UID在数据库层面限制数据读写，未登录仅持anon低权限（实际行级隔离需配合RLS策略配置，详见[数据库API（Database Data API）](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_23.html)）。模块独立可用，可灵活接入您的应用。本章介绍认证方式、Auth配置及SDK操作。
#### 认证方式
华为云RDS Supabase支持以下两种认证方式，详见[表1]。
 表1认证方式概览 
| 认证方式          | 适用场景                                                                         |
|:---|:---|
| 邮箱认证（SMTP**）** | 用户使用邮箱 + 密码注册与登录，系统通过SMTP发送确认邮件完成验证。适用于需要自主管理用户账号体系、面向通用用户的场景。                |
| GitHub OAuth     | 用户使用GitHub账号进行第三方单点登录（SSO），无需在应用内另行注册。适用于面向开发者、技术团队，或希望借助GitHub既有账号体系快速登录的场景。 |
   
![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/note_3.0-zh-cn.png)
华为云RDS Supabase**不支持**手机号/SMS、微信、支付宝、Google账号登录；GitHub是唯一支持的第三方OAuth登录方式。
#### 认证状态与RLS角色
认证模块与行级安全（RLS）联动，登录状态决定访问数据时所用的数据库角色，进而决定可见数据范围。
表2认证状态与RLS角色 
| 认证状态                        | RLS角色         | 说明                     |
|:---|:---|:---|
| 未登录 + Publishable Key       | anon        | 匿名用户，仅受anon策略约束。        |
| 已登录 + Publishable Key        | authenticated | 认证用户，受authenticated策略约束。 |
| Secret Key / Service Role Key | Bypass RLS  | 服务端高权限，绕过行级安全。          |
   
实际行级隔离需配合RLS策略配置，详见[数据库API（Database Data API）](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_23.html)。
#### Auth配置
Auth配置是控制台集中管理认证能力的入口，可在此完成认证方式的启停与参数调配：启用并配置邮箱认证、GitHub第三方登录，控制用户注册与匿名访问，设置各类邮件模板等。
Auth配置入口：单击Supabase应用名称，进入应用详情页，即可看到Auth配置入口，详细操作见[用户认证Auth配置管理](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_20.html)。
表3Auth配置类别 
| 配置类别        | 说明                                                                                                                                                                                                                   |
|:---|:---|
| 邮箱IDP（SMTP） | SMTP主机、端口、用户名、密码（授权码）、管理员邮箱、发件人姓名、邮箱自动确认、发件速率限制等，详见[配置IDP身份验证提供商（邮箱）](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_20.html#rds_supabase_20__zh-cn_topic_0000002659370536_section1085145413318)。    |
| GitHub IDP  | GitHub OAuth App的Client ID、Client Secret、回调URL，详见[配置IDP身份验证提供商（GitHub）](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_20.html#rds_supabase_20__zh-cn_topic_0000002659370536_section2517102212516)。 |
| 访问控制         | 站点URL、允许重定向的URL列表、是否允许新用户注册、是否允许匿名用户，详见[访问控制](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_20.html#rds_supabase_20__zh-cn_topic_0000002659370536_section43171733112316)。                           |
| 邮件模板        | 涵盖邮箱确认、邀请、密码重置、邮箱变更、魔法链接、重新认证等场景，模板可用Storage Bucket托管，详见[配置邮箱模板](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_20.html#rds_supabase_20__zh-cn_topic_0000002659370536_section3866164621614)。       |
   
![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/note_3.0-zh-cn.png)
邮件模板中的魔法链接对应无密码邮箱登录（通过signInWithOtp发送一次性登录链接）。华为云RDS Supabase当前主推邮箱密码认证，魔法链接模板为预置项，供按需扩展使用，本文不展开介绍。
#### 邮箱认证（SMTP）
SMTP（简单邮件传输协议）是发送邮件的标准协议，邮箱认证即依赖SMTP服务器发送确认与通知邮件。通过邮箱认证形成完整闭环：注册 → 登录 → 认证状态 → 更新用户（邮箱与密码） → 注销
邮箱认证围绕邮箱+密码与邮件验证构建，支持的核心业务场景与功能如下：
- **注册与登录**：用户以邮箱+密码注册、登录。
- **邮箱确认**：注册后发送确认邮件验证邮箱归属，防止伪造账号。
- **魔法链接登录**：无密码场景，发送一次性登录链接，点击即登录。
- **密码重置**：忘记密码时，通过邮箱重置链接恢复访问。
- **邮箱变更**：换绑邮箱时，向新邮箱发确认链接，确认后生效。
- **信息与会话维护**：更新邮箱/密码、监听登录状态、注销。
各流程邮件均经SMTP发送，模板可在控制台Auth配置中定制。
- **邮箱注册**
  ```
  const { data, error } = await supabase.auth.signUp({
    email: 'user@example.com', // 邮箱地址
    password: 'your-password', // 邮箱密码
  })
  ```
  调用后系统创建用户并发送确认邮件。若控制台开启了"邮箱自动确认"，邮箱即时验证通过，用户注册后即处于登录态；否则需点击确认邮件中的链接完成验证，方可登录获取会话。
  **前提：** 未开启"邮箱自动确认"时，注册依赖已配置且可达的SMTP服务发送确认邮件；若SMTP未配置或不可达，用户将无法收到确认邮件、无法完成注册。
  
- **邮箱登录**
  ```
  const { data, error } = await supabase.auth.signInWithPassword({
    email: 'user@example.com',  // 邮箱地址
    password: 'your-password',  // 邮箱密码
  })
  ```
  调用返回{ data, error }：成功时error为null、data含登录会话；失败时（如密码错误、用户不存在）error非空，根据该错误，判断并提示用户。
  ```
  if (error) {
    console.error('登录失败:', error.message)
    return
  }
  ```
  
- **监听认证状态**
  会话（session）是用户登录后的凭证，登录凭证（JWT）具备有效期；SDK会在凭证过期前自动续期、无需手动处理，TOKEN_REFRESHED事件在凭证续期时触发。
  可监听认证状态变化以联动界面。
  ```
  supabase.auth.onAuthStateChange((event, session) => {
    console.log('认证事件:', event)
    console.log('当前会话:', session)
  })
  ```
   表4邮箱认证状态事件 
  | 事件                  | 说明                 |
  |:---|:---|
  | INITIAL_SESSION     | 客户端初始化时触发，用于恢复已有会话。   |
  | SIGNED_IN             | 用户登录。                |
  | SIGNED_OUT             | 用户注销。               |
  | TOKEN_REFRESHED      | 登录凭证自动续期。             |
  | PASSWORD_RECOVERY | 密码恢复流程触发（用户请求重置密码时）。 |
  | USER_UPDATED          | 用户信息更新。              |
     
  
- **邮箱变更**
  ```
  const { data, error } = await supabase.auth.updateUser({ email: 'new-email@example.com' })
  if (error) {
    console.error('邮箱变更失败:', error.message)
    return
  }
  ```
  用户必须处于登录状态才能调用updateUser()。调用后系统向新邮箱发送"邮箱变更"确认邮件，用户须点击确认链接后新邮箱才正式生效；未确认前旧邮箱仍可用于登录。
  
- **密码重置**
  用户忘记密码时，可通过邮箱重置：先发送重置邮件，用户点击邮件中的重置链接回到应用后，再设置新密码。
  ```
  // 发送密码重置邮件
  const { data, error } = await supabase.auth.resetPasswordForEmail(
    'user@example.com',    // 邮箱地址
    { emailRedirectTo: 'https://your-app.com/reset-password' }
  )
  if (error) {
    console.error('发送重置邮件失败:', error.message)
    return
  }
  ```
  用户点击重置链接后，被重定向回应用并触发PASSWORD_RECOVERY事件，此时处于密码重置状态，可在重置页面调用updateUser设置新密码。
  ```
  // 用户输入新密码后重置
  const { data, error } = await supabase.auth.updateUser({ password: 'new-password' })
  if (error) {
    console.error('重置密码失败:', error.message)
    return
  }
  ```
  重置链接一次性有效；需在控制台Auth配置中启用邮箱认证并使用"密码恢复"邮件模板。密码可能因强度不足等被拒绝，请判断error并提示用户。
  
- **用户注销**
  ```
  // 默认登出当前用户在所有设备的会话
  const { error } = await supabase.auth.signOut()
  // 如仅登出当前会话（保留其他设备登录），显式指定 local
  const { error } = await supabase.auth.signOut({ scope: 'local' })
  ```
  signOut()默认scope为global，会登出该用户在所有设备的会话；若只想退出当前会话，须显式传{ scope: 'local' }。两种方式均会触发SIGNED_OUT事件。
  
- **魔法链接（无密码**登录**）**
  魔法链接（Magic Link）是一种无密码邮箱登录方式：用户输入邮箱，系统发送一封含一次性登录链接的邮件，用户点击链接即完成登录，无需记忆密码。适用于希望降低注册门槛、减少密码运维的场景。
  ```
  // 发送魔法链接邮件
  const { data, error } = await supabase.auth.signInWithOtp({
    email: 'user@example.com',    // 邮箱地址
    options: {
      emailRedirectTo: 'https://your-app.com/dashboard'
    }
  })
  if (error) {
    console.error('发送登录链接失败:', error.message)
    return
  }
  ```
  用户收到邮件后点击链接，即被重定向回应用并完成登录，随后触发SIGNED_IN事件；魔法链接一次性有效，登录后即失效。魔法链接依赖已配置且可达的SMTP服务，并使用控制台Auth配置中的"魔法链接"邮件模板。
  
 
#### GitHub OAuth（SSO单点登录）
OAuth是一种开放授权标准，允许用户使用已有的第三方账号登录应用，而无需在应用内另行设置密码。GitHub OAuth即通过GitHub账号实现第三方登录（常被类比为单点登录）：用户无需在应用内另行注册账号或设置密码，只需使用已有的GitHub账号授权一次即可登录应用，以GitHub作为可信身份来源。通过GitHub OAuth形成完整闭环：登录 → 认证状态 → 更新用户（邮箱与密码） → 注销
- **GitHub登录**
  调用后，SDK在浏览器端自动重定向至GitHub完成身份认证与授权；用户在GitHub确认后，GitHub回调携带授权码，应用据此换取会话，用户即处于登录态。整个登录过程由GitHub侧保管凭证，应用不接触用户密码。
  ```
  // 基本调用
  const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'github' })
  // 指定回调后重定向地址
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'github',
    options: { redirectTo: 'https://your-app.com/dashboard' }
  })
  ```
  回调地址分两层：
  - GitHub OAuth App的Authorization callback URL：GitHub完成认证后携带授权码回传至Supabase的地址。
  
  - redirectTo：Supabase处理完授权码后跳转回应用的业务页面地址（如上方示例）。
   
- **监听认证状态**
  ```
  supabase.auth.onAuthStateChange((event, session) => {
    console.log('认证事件:', event)
    console.log('当前会话:', session)
  })
  ```
  监听方式与事件清单与邮箱认证完全一致，详见[表4]。
  
- **邮箱变更**
  ```
  const { data, error } = await supabase.auth.updateUser({ email: 'new-email@example.com' })
  if (error) {
    console.error('邮箱变更失败:', error.message)
    return
  }
  ```
  用户必须处于登录状态才能调用updateUser()。调用后系统向新邮箱发送"邮箱变更"确认邮件，用户须点击确认链接后新邮箱才正式生效。用法与邮箱认证一致。
  
- **密码重置**
  ```
  // 发送密码重置邮件
  const { data, error } = await supabase.auth.resetPasswordForEmail(
    'user@example.com',    // 邮箱地址
    { emailRedirectTo: 'https://your-app.com/reset-password' }
  )
  if (error) {
    console.error('发送重置邮件失败:', error.message)
    return
  }
  ```
  用户点击重置链接后触发PASSWORD_RECOVERY事件，在重置页面调用updateUser设置新密码。通过GitHub SSO登录的用户在应用内没有密码，密码重置项可用于为其设置应用内密码；若始终仅用GitHub登录，可跳过密码重置。
  
- **用户注销**
  ```
  const { error } = await supabase.auth.signOut()
  ```
  signOut()默认scope为global，会登出该用户在所有设备的会话；若只想退出当前会话，须显式传{ scope: 'local' }。
  
 
#### 参考文档
以下为Supabase开源社区的相关资料，仅供参考。
- [Supabase Auth指南](https://supabase.com/docs/guides/auth)
- [Supabase JavaScript SDK（Auth API）](https://supabase.com/docs/reference/javascript/auth-api)
- [Supabase Auth signUp](https://supabase.com/docs/reference/javascript/auth-signup)
- [Supabase Auth signInWithPassword](https://supabase.com/docs/reference/javascript/auth-signinwithpassword)
- [Supabase Auth signInWithOAuth](https://supabase.com/docs/reference/javascript/auth-signinwithoauth)
- [Supabase Auth updateUser](https://supabase.com/docs/reference/javascript/auth-updateuser)
- [Supabase Auth signOut](https://supabase.com/docs/reference/javascript/auth-signout)
- [Supabase Auth onAuthStateChange](https://supabase.com/docs/reference/javascript/auth-onauthstatechange)
 
