Supabase认证概述 #
一、认证系统架构 #
1.1 整体架构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 客户端应用 │
│ Web / Mobile / Desktop / Server │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Supabase Auth │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Email/Pass │ │ OAuth │ │ Magic Link │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Phone │ │ SAML SSO │ │ Anonymous │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PostgreSQL │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ auth.users │ │auth.sessions│ │auth.identit │ │
│ │ │ │ │ │ ies │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.2 认证方式 #
| 认证方式 | 说明 | 适用场景 |
|---|---|---|
| Email/Password | 邮箱密码登录 | 传统应用 |
| OAuth | 第三方登录 | 快速登录 |
| Magic Link | 无密码登录 | 安全便捷 |
| Phone | 手机号验证码 | 移动应用 |
| SAML SSO | 企业单点登录 | 企业应用 |
| Anonymous | 匿名登录 | 试用体验 |
1.3 认证流程 #
text
用户登录流程
├── 1. 用户提交凭证
├── 2. Auth服务验证
├── 3. 生成JWT令牌
├── 4. 返回会话信息
│ ├── access_token
│ ├── refresh_token
│ └── user信息
├── 5. 客户端存储会话
└── 6. 后续请求携带token
二、用户表结构 #
2.1 auth.users表 #
sql
-- Supabase内置用户表
SELECT * FROM auth.users;
-- 主要字段
┌─────────────────┬──────────────────────────────┐
│ 字段 │ 说明 │
├─────────────────┼──────────────────────────────┤
│ id │ UUID主键 │
│ email │ 邮箱地址 │
│ encrypted_pass │ 加密密码 │
│ email_confirmed │ 邮箱验证时间 │
│ created_at │ 创建时间 │
│ updated_at │ 更新时间 │
│ last_sign_in_at │ 最后登录时间 │
│ raw_user_meta │ 用户元数据(JSON) │
│ is_anonymous │ 是否匿名用户 │
└─────────────────┴──────────────────────────────┘
2.2 auth.sessions表 #
sql
-- 会话表
SELECT * FROM auth.sessions;
-- 主要字段
┌─────────────────┬──────────────────────────────┐
│ 字段 │ 说明 │
├─────────────────┼──────────────────────────────┤
│ id │ UUID主键 │
│ user_id │ 用户ID │
│ access_token │ 访问令牌 │
│ refresh_token │ 刷新令牌 │
│ expires_at │ 过期时间 │
│ created_at │ 创建时间 │
└─────────────────┴──────────────────────────────┘
2.3 auth.identities表 #
sql
-- 身份表(OAuth等)
SELECT * FROM auth.identities;
-- 主要字段
┌─────────────────┬──────────────────────────────┐
│ 字段 │ 说明 │
├─────────────────┼──────────────────────────────┤
│ id │ 身份ID │
│ user_id │ 用户ID │
│ provider │ 提供商(github/google等) │
│ identity_data │ 身份数据(JSON) │
└─────────────────┴──────────────────────────────┘
2.4 创建用户资料表 #
sql
-- 创建用户资料表
CREATE TABLE public.profiles (
id UUID REFERENCES auth.users(id) PRIMARY KEY,
updated_at TIMESTAMPTZ DEFAULT NOW(),
username TEXT UNIQUE,
full_name TEXT,
avatar_url TEXT,
website TEXT,
bio TEXT,
CONSTRAINT username_length CHECK (char_length(username) >= 3)
);
-- 自动创建用户资料的触发器
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, full_name, avatar_url)
VALUES (
NEW.id,
NEW.raw_user_meta_data->>'full_name',
NEW.raw_user_meta_data->>'avatar_url'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- 创建触发器
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.handle_new_user();
三、JWT令牌 #
3.1 JWT结构 #
text
JWT结构: Header.Payload.Signature
Header:
{
"alg": "HS256",
"typ": "JWT"
}
Payload:
{
"iss": "https://xxx.supabase.co/auth/v1",
"sub": "user-uuid",
"aud": "authenticated",
"exp": 1234567890,
"iat": 1234567890,
"email": "user@example.com",
"role": "authenticated"
}
Signature:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
jwt-secret
)
3.2 令牌类型 #
text
令牌类型
├── Access Token
│ ├── 用于API请求认证
│ ├── 有效期短(默认1小时)
│ ├── 包含用户信息
│ └── 存储在内存/localStorage
│
└── Refresh Token
├── 用于刷新Access Token
├── 有效期长(默认7天)
├── 不包含敏感信息
└── 存储在数据库和客户端
3.3 令牌刷新 #
typescript
// 自动刷新(默认开启)
const supabase = createClient(url, key, {
auth: {
autoRefreshToken: true, // 自动刷新
persistSession: true, // 持久化会话
}
})
// 手动刷新
const { data, error } = await supabase.auth.refreshSession()
// 或只刷新token
const { data, error } = await supabase.auth.refreshAccessToken()
四、会话管理 #
4.1 获取会话 #
typescript
// 获取当前会话
const { data: { session }, error } = await supabase.auth.getSession()
// 监听会话变化
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
console.log('Auth event:', event)
console.log('Session:', session)
}
)
// 取消监听
subscription.unsubscribe()
4.2 会话事件 #
typescript
supabase.auth.onAuthStateChange((event, session) => {
switch (event) {
case 'INITIAL_SESSION':
// 初始会话加载
break
case 'SIGNED_IN':
// 用户登录
break
case 'SIGNED_OUT':
// 用户登出
break
case 'PASSWORD_RECOVERY':
// 密码恢复
break
case 'TOKEN_REFRESHED':
// Token刷新
break
case 'USER_UPDATED':
// 用户信息更新
break
}
})
4.3 多设备管理 #
typescript
// 获取所有会话
const { data, error } = await supabase.auth.getSessions()
// 登出其他设备
const { error } = await supabase.auth.signOut({
scope: 'others'
})
// 登出所有设备
const { error } = await supabase.auth.signOut({
scope: 'global'
})
五、权限级别 #
5.1 用户角色 #
text
Supabase用户角色
├── anon
│ ├── 匿名用户
│ ├── 受RLS限制
│ └── 公开API Key
│
├── authenticated
│ ├── 已认证用户
│ ├── 受RLS限制
│ └── 需要登录
│
└── service_role
├── 服务角色
├── 绕过RLS
└── 仅服务端使用
5.2 在SQL中获取用户信息 #
sql
-- 获取当前用户ID
SELECT auth.uid();
-- 获取当前用户邮箱
SELECT auth.jwt() ->> 'email';
-- 在RLS策略中使用
CREATE POLICY "Users can only see own data"
ON profiles FOR SELECT
USING (auth.uid() = id);
5.3 自定义JWT声明 #
sql
-- 添加自定义JWT声明
CREATE OR REPLACE FUNCTION auth.jwt()
RETURNS JSONB AS $$
DECLARE
claims JSONB;
BEGIN
SELECT
COALESCE(
jsonb_build_object(
'user_role', role,
'user_plan', plan
),
'{}'::jsonb
)
INTO claims
FROM profiles
WHERE id = auth.uid();
RETURN claims;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
六、安全最佳实践 #
6.1 密码安全 #
text
密码安全建议
├── 最小长度8位
├── 包含大小写字母
├── 包含数字和特殊字符
├── 不使用常见密码
├── 定期更换密码
└── 启用多因素认证
6.2 Token安全 #
typescript
// 安全存储配置
const supabase = createClient(url, key, {
auth: {
storage: {
getItem: (key) => {
// 使用安全存储
return secureStorage.getItem(key)
},
setItem: (key, value) => {
secureStorage.setItem(key, value)
},
removeItem: (key) => {
secureStorage.removeItem(key)
},
},
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
},
})
6.3 HTTPS要求 #
text
安全要求
├── 生产环境必须使用HTTPS
├── Cookie设置Secure标志
├── 防止中间人攻击
└── 保护Token传输
七、认证配置 #
7.1 Dashboard配置 #
text
Dashboard > Authentication > Providers
可配置项
├── Email
│ ├── 启用/禁用
│ ├── 邮箱验证要求
│ └── 密码策略
│
├── OAuth Providers
│ ├── GitHub
│ ├── Google
│ ├── Facebook
│ ├── Twitter
│ └── 更多...
│
└── 其他设置
├── Magic Link
├── Phone Auth
└── Anonymous Auth
7.2 URL配置 #
text
Dashboard > Authentication > URL Configuration
配置项
├── Site URL
│ └── 应用主URL
│
├── Redirect URLs
│ └── 允许的回调URL列表
│
└── Email Settings
├── SMTP配置
└── 邮件模板
八、常见问题 #
8.1 会话丢失 #
typescript
// 检查会话状态
const { data: { session } } = await supabase.auth.getSession()
if (!session) {
// 会话丢失,需要重新登录
await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'password'
})
}
8.2 Token过期 #
typescript
// 自动刷新处理
supabase.auth.onAuthStateChange((event) => {
if (event === 'TOKEN_REFRESHED') {
console.log('Token refreshed successfully')
}
})
// 手动刷新
try {
await supabase.auth.refreshSession()
} catch (error) {
// 刷新失败,需要重新登录
await supabase.auth.signInWithPassword(...)
}
九、总结 #
认证系统要点:
| 概念 | 说明 |
|---|---|
| 用户表 | auth.users |
| 会话 | JWT + Refresh Token |
| 角色 | anon, authenticated, service_role |
| 存储 | localStorage / 安全存储 |
| 刷新 | 自动刷新 / 手动刷新 |
下一步,让我们学习邮箱密码认证!
最后更新:2026-03-28