在 Flutter 中接入 Supabase 邮箱登录(分步指南)
本文说明如何在一个 Flutter 应用里,使用 Supabase Auth 实现 邮箱 + 密码 的注册与登录,并简要说明初始化、会话与登出等常见流程。适用于已熟悉 Flutter 基础、准备在客户端直连 Supabase 的开发者。
你将完成什么
- 在 Supabase 控制台开启邮箱登录并完成必要配置
- (可选)通过 Resend 自定义 SMTP,用你自己的域名发送验证邮件
- 在 Flutter 项目中集成
supabase_flutter并完成初始化 - 实现注册、登录、登出,并了解邮箱确认与重定向注意事项
前置条件
- 已安装 Flutter SDK(建议稳定版)
- 已注册 Supabase 并创建一个项目
- 本地能运行
flutter create与flutter run
第一步:在 Supabase 中配置邮箱认证
- 打开 Supabase 控制台,进入你的项目。
- 左侧进入 Authentication → Providers。
- 找到 Email,保持开启(默认通常已开启)。按需配置:
- Confirm email:若开启,用户注册后需点击邮件里的链接才能登录;开发阶段可先关闭以便快速联调,上线前再打开。
- 进入 Authentication → URL Configuration(或项目 Authentication 设置中的站点 URL 相关项):
- Site URL:填写你应用的「官方」地址;本地调试可先用
http://localhost或占位,具体以你使用的深度链接方案为准。 - Redirect URLs:添加邮件确认、魔法链接等会跳转到的地址。Flutter 若使用自定义 scheme(如
com.example.app://login-callback),需把完整 URL 加入允许列表。
- Site URL:填写你应用的「官方」地址;本地调试可先用
若使用「邮箱确认」,务必保证邮件里的确认链接能跳回你的 App(自定义 URL Scheme 或 Universal Links),否则用户确认后可能无法回到应用。
(可选)使用 Resend 配置自定义 SMTP
Supabase 自带的邮件服务便于开发,但生产环境往往希望:用自己的域名发信、改善送达率、统一品牌与退信处理。可以把 Resend 作为 SMTP 提供商,在 Supabase 里开启「自定义 SMTP」,由 Resend 代发注册确认、重置密码等 Auth 邮件。
官方对照文档:Resend:通过 SMTP 连接 Supabase、Supabase:自定义 SMTP。
1. 在 Resend 中准备域名与 API Key
- 注册并登录 Resend。
- 进入 Domains,添加你的发信域名(如
example.com)。 - 按提示在 DNS 服务商处添加 SPF、DKIM等记录,直到 Resend 显示域名已验证。
- 进入 API Keys,创建一个具有发送权限的密钥(形如
re_...),仅保存在服务端或控制台配置中,不要写进 Flutter 客户端。
发件人地址必须使用已验证域名下的邮箱,例如 auth@yourdomain.com。
2. 在 Supabase 中启用自定义 SMTP
- 打开 Supabase 控制台 →你的项目。
- 进入 Project Settings(项目设置)→ Authentication(或 Auth)中找到 SMTP Settings(自定义 SMTP / Custom SMTP)。
- 打开 Enable Custom SMTP(启用自定义 SMTP)。
- 按下面填写(与 Resend SMTP 说明 一致):
| 字段 | 填写内容 |
|---|---|
| Host | smtp.resend.com |
| Port | 465(推荐,SSL/TLS)或 587(STARTTLS,视控制台选项而定) |
| Username | resend(固定为这个字面用户名) |
| Password | 你在 Resend 创建的 API Key |
| Sender email | 已验证域名下的地址,如 auth@yourdomain.com |
| Sender name | 可选,如 My App |
- 保存设置。若控制台提供「发送测试邮件」,可先测一封再让用户走注册流程。
3. 与 Flutter / Auth 流程的关系
- SMTP 只影响 邮件如何从 Supabase 发出;Flutter 端 仍使用同一套
signUp/signInWithPassword,无需为 Resend 改客户端代码。 - 若你开启了 Confirm email,用户收到的确认邮件会改为从你的域名发出;Site URL、Redirect URLs 仍须在 Supabase Authentication → URL Configuration 中正确配置。
- 若邮件进垃圾箱,除文案与域名信誉外,需确认 Resend 域名验证已通过、发件人与域名一致。
4. 常见问题
| 现象 | 建议排查 |
|---|---|
| 保存 SMTP 后仍收不到信 | Resend 控制台是否有发送记录;域名是否已验证;API Key 是否有效 |
| 提示认证失败 | Username 必须为 resend;Password 为 API Key,不是登录密码 |
| 发件人被拒 | 发件人邮箱是否属于 Resend 中已验证的域名 |
第二步:获取项目 URL 与 anon 公钥
- 在 Supabase 控制台打开 Project Settings → API。
- 记下:
- Project URL(形如
https://xxxx.supabase.co) - anon public key(客户端使用;不要把
service_role密钥写进 App)
- Project URL(形如
第三步:创建 Flutter 工程并添加依赖
flutter create my_app
cd my_app
在 pubspec.yaml 的 dependencies 中加入(版本号以 pub.dev 上 supabase_flutter 最新版 为准):
dependencies:
flutter:
sdk: flutter
supabase_flutter: ^2.8.0
然后执行:
flutter pub get
第四步:初始化 Supabase(main.dart)
在 main 中先完成 WidgetsFlutterBinding.ensureInitialized(),再调用 Supabase.initialize:
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: 'https://YOUR_PROJECT_REF.supabase.co',
anonKey: 'YOUR_ANON_PUBLIC_KEY',
);
runApp(const MyApp());
}
将 YOUR_PROJECT_REF 与 YOUR_ANON_PUBLIC_KEY 换成第二步中的值。
安全提示:示例为便于理解直接写在代码里;生产环境建议使用 --dart-define 或远程配置注入,避免把密钥硬编码进仓库。
第五步:注册(邮箱 + 密码)
在用户提交注册表单后调用:
Future<void> signUpWithEmail({
required String email,
required String password,
}) async {
final response = await Supabase.instance.client.auth.signUp(
email: email,
password: password,
);
final user = response.user;
final session = response.session;
if (user == null) {
// 例如:开启了邮箱确认,需先查邮件
return;
}
// session 非空表示已可直接登录(例如未强制邮箱确认时)
if (session != null) {
// 进入已登录状态 UI
}
}
- 若项目 要求邮箱确认:
session可能为null,需提示用户去邮箱点击链接;确认成功后再登录或自动拿到会话(取决于你的重定向与深度链接配置)。
第六步:登录(邮箱 + 密码)
Future<void> signInWithEmail({
required String email,
required String password,
}) async {
final response = await Supabase.instance.client.auth.signInWithPassword(
email: email,
password: password,
);
final session = response.session;
if (session == null) {
// 处理未返回会话(账号未确认、密码错误等,可结合 AuthException)
return;
}
// 已登录:session.user 可用
}
捕获 AuthException 可向用户展示友好错误信息(邮箱未确认、密码错误等)。
第七步:监听登录状态(可选但推荐)
用 Stream 或 onAuthStateChange 驱动界面在「未登录 / 已登录」之间切换:
@override
void initState() {
super.initState();
Supabase.instance.client.auth.onAuthStateChange.listen((data) {
final event = data.event;
final session = data.session;
switch (event) {
case AuthChangeEvent.signedIn:
// 跳转首页或刷新状态
break;
case AuthChangeEvent.signedOut:
// 跳转登录页
break;
default:
break;
}
});
}
也可使用 Supabase.instance.client.auth.currentSession 在启动时判断是否已有会话。
第八步:登出
Future<void> signOut() async {
await Supabase.instance.client.auth.signOut();
}
第九步:在 UI 中拿到当前用户
final user = Supabase.instance.client.auth.currentUser;
final email = user?.email;
常见问题简表
| 现象 | 可能原因 |
|---|---|
| 注册成功但无法登录 | 开启了邮箱确认,需先完成邮件验证 |
| 登录报邮箱未验证 | 同上;检查垃圾邮件箱与 Supabase 邮件模板 |
| 邮件链接打开后无法回 App | Redirect URLs 未包含你的 scheme,或深度链接未配置 |
| 密钥泄露风险 | 勿提交 service_role;anon 可公开但应用层仍需 RLS 保护数据 |
与 Row Level Security(RLS)的关系
客户端使用 anon key 访问数据库时,务必在 Supabase 中为相关表配置 RLS 与策略,例如仅允许 auth.uid() 对应用户读写自己的行。否则即使登录成功,数据仍可能暴露或无法写入——这是后端配置问题,不单是 Flutter 代码能解决的。
小结
- 控制台开启 Email,并配置 Site URL 与 Redirect URLs。
- Flutter 引入
supabase_flutter,在main里Supabase.initialize。 - 使用
signUp/signInWithPassword/signOut,并用onAuthStateChange驱动界面。 - 生产环境注意密钥注入、邮箱确认流程与 RLS。
按上述步骤即可在 Flutter 中跑通 Supabase 邮箱登录;若你后续需要「忘记密码」「OAuth」「手机号」等,可在同一 Auth 模块上扩展。