← 返回文章列表
开发笔记

在 Flutter 中接入 Supabase 邮箱登录(分步指南)

本文说明如何在一个 Flutter 应用里,使用 Supabase Auth 实现 邮箱 + 密码 的注册与登录,并简要说明初始化、会话与登出等常见流程。适用于已熟悉 Flutter 基础、准备在客户端直连 Supabase 的开发者。

你将完成什么

  • 在 Supabase 控制台开启邮箱登录并完成必要配置
  • (可选)通过 Resend 自定义 SMTP,用你自己的域名发送验证邮件
  • 在 Flutter 项目中集成 supabase_flutter 并完成初始化
  • 实现注册、登录、登出,并了解邮箱确认与重定向注意事项

前置条件

  • 已安装 Flutter SDK(建议稳定版)
  • 已注册 Supabase 并创建一个项目
  • 本地能运行 flutter createflutter run

第一步:在 Supabase 中配置邮箱认证

  1. 打开 Supabase 控制台,进入你的项目。
  2. 左侧进入 AuthenticationProviders
  3. 找到 Email,保持开启(默认通常已开启)。按需配置:
    • Confirm email:若开启,用户注册后需点击邮件里的链接才能登录;开发阶段可先关闭以便快速联调,上线前再打开。
  4. 进入 AuthenticationURL Configuration(或项目 Authentication 设置中的站点 URL 相关项):
    • Site URL:填写你应用的「官方」地址;本地调试可先用 http://localhost 或占位,具体以你使用的深度链接方案为准。
    • Redirect URLs:添加邮件确认、魔法链接等会跳转到的地址。Flutter 若使用自定义 scheme(如 com.example.app://login-callback),需把完整 URL 加入允许列表。

若使用「邮箱确认」,务必保证邮件里的确认链接能跳回你的 App(自定义 URL Scheme 或 Universal Links),否则用户确认后可能无法回到应用。

(可选)使用 Resend 配置自定义 SMTP

Supabase 自带的邮件服务便于开发,但生产环境往往希望:用自己的域名发信、改善送达率、统一品牌与退信处理。可以把 Resend 作为 SMTP 提供商,在 Supabase 里开启「自定义 SMTP」,由 Resend 代发注册确认、重置密码等 Auth 邮件。

官方对照文档:Resend:通过 SMTP 连接 SupabaseSupabase:自定义 SMTP

1. 在 Resend 中准备域名与 API Key

  1. 注册并登录 Resend
  2. 进入 Domains,添加你的发信域名(如 example.com)。
  3. 按提示在 DNS 服务商处添加 SPF、DKIM等记录,直到 Resend 显示域名已验证。
  4. 进入 API Keys,创建一个具有发送权限的密钥(形如 re_...),仅保存在服务端或控制台配置中,不要写进 Flutter 客户端。

发件人地址必须使用已验证域名下的邮箱,例如 auth@yourdomain.com

2. 在 Supabase 中启用自定义 SMTP

  1. 打开 Supabase 控制台 →你的项目。
  2. 进入 Project Settings(项目设置)→ Authentication(或 Auth)中找到 SMTP Settings(自定义 SMTP / Custom SMTP)。
  3. 打开 Enable Custom SMTP(启用自定义 SMTP)。
  4. 按下面填写(与 Resend SMTP 说明 一致):
字段填写内容
Hostsmtp.resend.com
Port465(推荐,SSL/TLS)或 587(STARTTLS,视控制台选项而定)
Usernameresend(固定为这个字面用户名)
Password你在 Resend 创建的 API Key
Sender email已验证域名下的地址,如 auth@yourdomain.com
Sender name可选,如 My App
  1. 保存设置。若控制台提供「发送测试邮件」,可先测一封再让用户走注册流程。

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 公钥

  1. 在 Supabase 控制台打开 Project SettingsAPI
  2. 记下:
    • Project URL(形如 https://xxxx.supabase.co
    • anon public key(客户端使用;不要service_role 密钥写进 App)

第三步:创建 Flutter 工程并添加依赖

flutter create my_app
cd my_app

pubspec.yamldependencies 中加入(版本号以 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_REFYOUR_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 可向用户展示友好错误信息(邮箱未确认、密码错误等)。

第七步:监听登录状态(可选但推荐)

StreamonAuthStateChange 驱动界面在「未登录 / 已登录」之间切换:

@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 邮件模板
邮件链接打开后无法回 AppRedirect URLs 未包含你的 scheme,或深度链接未配置
密钥泄露风险勿提交 service_role;anon 可公开但应用层仍需 RLS 保护数据

与 Row Level Security(RLS)的关系

客户端使用 anon key 访问数据库时,务必在 Supabase 中为相关表配置 RLS 与策略,例如仅允许 auth.uid() 对应用户读写自己的行。否则即使登录成功,数据仍可能暴露或无法写入——这是后端配置问题,不单是 Flutter 代码能解决的。

小结

  1. 控制台开启 Email,并配置 Site URLRedirect URLs
  2. Flutter 引入 supabase_flutter,在 mainSupabase.initialize
  3. 使用 signUp / signInWithPassword / signOut,并用 onAuthStateChange 驱动界面。
  4. 生产环境注意密钥注入、邮箱确认流程与 RLS

按上述步骤即可在 Flutter 中跑通 Supabase 邮箱登录;若你后续需要「忘记密码」「OAuth」「手机号」等,可在同一 Auth 模块上扩展。