跳到主要内容
给我们的新朋友:

Logto 是一个为现代应用和 SaaS 产品设计的 Auth0 替代方案。它提供 Cloud开源 服务,帮助你快速启动身份和管理 (IAM) 系统。享受认证 (Authentication)、授权 (Authorization) 和多租户管理 一体化

我们建议从 Logto Cloud 上的免费开发租户开始。这可以让你轻松探索所有功能。

在本文中,我们将介绍使用 FlutterLogto 快速构建 SendGrid 登录体验(用户认证 (Authentication))的步骤。

先决条件

  • 一个正在运行的 Logto 实例。查看 介绍页面 以开始。
  • Flutter 的基本知识。
  • 一个可用的 SendGrid 账户。

在 Logto 中创建一个应用程序

Logto 基于 OpenID Connect (OIDC) 认证 (Authentication) 和 OAuth 2.0 授权 (Authorization)。它支持跨多个应用程序的联合身份管理,通常称为单点登录 (SSO)。

要创建你的 Native app 应用程序,只需按照以下步骤操作:

  1. 打开 Logto Console。在“开始使用”部分,点击“查看全部”链接以打开应用程序框架列表。或者,你可以导航到 Logto Console > Applications,然后点击“创建应用程序”按钮。 开始使用
  2. 在打开的模态窗口中,点击“Native app”部分,或使用左侧的快速过滤复选框过滤所有可用的“Native app”框架。点击 "Flutter" 框架卡片以开始创建你的应用程序。 框架
  3. 输入应用程序名称,例如“Bookstore”,然后点击“创建应用程序”。

🎉 太棒了!你刚刚在 Logto 中创建了你的第一个应用程序。你将看到一个祝贺页面,其中包含详细的集成指南。按照指南查看你的应用程序中的体验将会是什么样的。

集成 Logto SDK

提示:
  • SDK 包可在 pub.dev 和 Logto GitHub 仓库 上获取。
  • 示例项目使用 Flutter material 构建。你可以在 pub.dev 上找到它。
  • 此 SDK 兼容 iOS、Android 和 Web 平台上的 Flutter 应用程序。与其他平台的兼容性尚未测试。

安装

你可以使用 pub 包管理器直接安装 logto_dart_sdk package。 在你的项目根目录下运行以下命令:

flutter pub add logto_dart_sdk

或者将以下内容添加到你的 pubspec.yaml 文件中:

dependencies:
logto_dart_sdk: ^3.0.0

然后运行:

flutter pub get

依赖和配置

SDK 版本兼容性

Logto SDK 版本Dart SDK 版本Dart 3.0 兼容性
< 2.0.0>= 2.17.6 < 3.0.0false
>= 2.0.0 < 3.0.0>= 3.0.0true
>= 3.0.0>= 3.6.0true

flutter_secure_storage 设置

在底层,这个 SDK 使用 flutter_secure_storage 来实现跨平台的持久安全令牌存储。

  • iOS 使用 Keychain
  • Android 使用 AES 加密。

配置 Android 版本

在项目的 android/app/build.gradle 文件中,将 android:minSdkVersion 设置为 >= 18

build.gradle
  android {
...

defaultConfig {
...
minSdkVersion 18
...
}
}

禁用 Android 上的自动备份

默认情况下,Android 会在 Google Drive 上备份数据。这可能导致异常 java.security.InvalidKeyException:Failed 解包密钥。为避免这种情况,

  1. 要禁用自动备份,请转到应用程序的清单文件,并将 android:allowBackupandroid:fullBackupContent 属性设置为 false

    AndroidManifest.xml
    <manifest ... >
    ...
    <application
    android:allowBackup="false"
    android:fullBackupContent="false"
    ...
    >
    ...
    </application>
    </manifest>

  2. FlutterSecureStorage 中排除 sharedprefs

    如果你需要为应用程序保留 android:fullBackupContent 而不是禁用它,可以从备份中排除 sharedprefs 目录。 请参阅 Android 文档 了解更多详细信息。

    在你的 AndroidManifest.xml 文件中,向 <application> 元素添加 android:fullBackupContent 属性,如以下示例所示。此属性指向一个包含备份规则的 XML 文件。

    AndroidManifest.xml
    <application ...
    android:fullBackupContent="@xml/backup_rules">
    </application>

    res/xml/ 目录中创建一个名为 @xml/backup_rules 的 XML 文件。在此文件中,使用 <include><exclude> 元素添加规则。以下示例备份所有共享首选项,除了 device.xml:

    @xml/backup_rules
    <?xml version="1.0" encoding="utf-8"?>
    <full-backup-content>
    <exclude domain="sharedpref" path="FlutterSecureStorage"/>
    </full-backup-content>

请查看 flutter_secure_storage 以获取更多详细信息。

flutter_web_auth_2 设置

在幕后,这个 SDK 使用 flutter_web_auth_2 来通过 Logto 认证用户。这个包提供了一种简单的方法,通过系统 webview 或浏览器来使用 Logto 认证用户。

这个插件在 iOS 12+ 和 macOS 10.15+ 上使用 ASWebAuthenticationSession,在 iOS 11 上使用 SFAuthenticationSession,在 Android 上使用 Chrome Custom Tabs,并在 Web 上打开一个新窗口。

  • iOS:无需额外设置

  • Android:在 Android 上注册回调 URL

    为了从 Logto 的登录网页捕获回调 URL,你需要在 AndroidManifest.xml 文件中注册你的登录 redirectUri。

    AndroidManifest.xml
      <manifest>
    <application>
    <activity
    android:name="com.linusu.flutter_web_auth_2.CallbackActivity"
    android:exported="true">
    <intent-filter android:label="flutter_web_auth_2">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="YOUR_CALLBACK_URL_SCHEME_HERE" />
    </intent-filter>
    </activity>
    </application>
    </manifest>
  • Web 浏览器:创建一个端点来处理回调 URL

    如果你使用的是 Web 平台,你需要创建一个端点来处理回调 URL,并使用 postMessage API 将其发送回应用程序。

    callback.html
    <!doctype html>
    <title>认证完成</title>
    <p>认证已完成。如果没有自动发生,请关闭窗口。</p>
    <script>
    function postAuthenticationMessage() {
    const message = {
    'flutter-web-auth-2': window.location.href,
    };

    if (window.opener) {
    window.opener.postMessage(message, window.location.origin);
    window.close();
    } else if (window.parent && window.parent !== window) {
    window.parent.postMessage(message, window.location.origin);
    } else {
    localStorage.setItem('flutter-web-auth-2', window.location.href);
    window.close();
    }
    }

    postAuthenticationMessage();
    </script>

请查看 flutter_web_auth_2 包中的设置指南以获取更多详细信息。

集成

初始化 LogtoClient

导入 logto_dart_sdk 包并在应用程序的根部初始化 LogtoClient 实例。

lib/main.dart
import 'package:logto_dart_sdk/logto_dart_sdk.dart';
import 'package:http/http.dart' as http;

void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);


Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Logto Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;


State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
late LogtoClient logtoClient;

void render() {
// 状态变化
}

// LogtoConfig
final logtoConfig = const LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>"
);

void _init() {
logtoClient = LogtoClient(
config: logtoConfig,
httpClient: http.Client(), // 可选的 http 客户端
);
render();
}


void initState() {
super.initState();
_init();
}

// ...
}

实现登录

在我们深入细节之前,这里是终端用户体验的快速概述。登录过程可以简化如下:

  1. 你的应用调用登录方法。
  2. 用户被重定向到 Logto 登录页面。对于原生应用,将打开系统浏览器。
  3. 用户登录并被重定向回你的应用(配置为重定向 URI)。

关于基于重定向的登录

  1. 此认证 (Authentication) 过程遵循 OpenID Connect (OIDC) 协议,Logto 强制执行严格的安全措施以保护用户登录。
  2. 如果你有多个应用程序,可以使用相同的身份提供商 (IdP)(日志 (Logto))。一旦用户登录到一个应用程序,当用户访问另一个应用程序时,Logto 将自动完成登录过程。

要了解有关基于重定向的登录的原理和好处的更多信息,请参阅 Logto 登录体验解释


在开始之前,你需要在管理控制台为你的应用程序添加一个重定向 URI。

让我们切换到 Logto Console 的应用详情页面。添加一个重定向 URI io.logto://callback 并点击“保存更改”。

Logto Console 中的重定向 URI
  • 对于 iOS,重定向 URI 方案并不重要,因为 ASWebAuthenticationSession 类会监听重定向 URI,无论它是否注册。
  • 对于 Android,重定向 URI 方案必须在 AndroidManifest.xml 文件中注册。

配置好重定向 URI 后,我们在页面上添加一个登录按钮,该按钮将调用 logtoClient.signIn API 来启动 Logto 登录流程:

lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
// ...
final redirectUri = 'io.logto://callback';


Widget build(BuildContext context) {
// ...

Widget signInButton = TextButton(
onPressed: () async {
await logtoClient.signIn(redirectUri);
render();
},
child: const Text('Sign In'),
);

return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SelectableText('My Demo App'),
signInButton,
],
),
),
);
}
}

实现登出

让我们切换到 Logto Console 的应用详情页面。添加一个注销后重定向 URI io.logto://callback,然后点击“保存更改”。

Logto Console 中的注销后重定向 URI

注销后重定向 URI 是一个 OAuth 2.0 概念,意味着在注销后应该重定向的位置。

现在让我们在主页上添加一个登出按钮,以便用户可以从你的应用程序中登出。

lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
// ...

final postSignOutRedirectUri = 'io.logto//home';


Widget build(BuildContext context) {
// ...

Widget signOutButton = TextButton(
onPressed: () async {
await logtoClient.signOut(postSignOutRedirectUri);
render();
},
child: const Text('Sign Out'),
);

return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SelectableText('My Demo App'),
signInButton,
signOutButton,
],
),
),
);
}
}

处理认证 (Authentication) 状态

Logto SDK 提供了一个异步方法来检查认证 (Authentication) 状态。该方法是 logtoClient.isAuthenticated。该方法返回一个布尔值,如果用户已认证 (Authentication),则返回 true,否则返回 false

在示例中,我们根据认证 (Authentication) 状态有条件地渲染登录和登出按钮。现在让我们更新 Widget 中的 render 方法以处理状态变化:

lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
// ...
bool? isAuthenticated = false;

void render() {
setState(() async {
isAuthenticated = await logtoClient.isAuthenticated;
});
}


Widget build(BuildContext context) {
// ...

return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SelectableText('My Demo App'),
isAuthenticated == true ? signOutButton : signInButton,
],
),
),
);
}
}

检查点:测试你的应用程序

现在,你可以测试你的应用程序:

  1. 运行你的应用程序,你将看到登录按钮。
  2. 点击登录按钮,SDK 将初始化登录过程并将你重定向到 Logto 登录页面。
  3. 登录后,你将被重定向回你的应用程序,并看到登出按钮。
  4. 点击登出按钮以清除令牌存储并登出。

添加 SendGrid 连接器

Email 连接器是一种用于发送一次性密码 (OTP) 的方法,用于认证 (Authentication)。它支持 电子邮件地址 验证,以支持无密码认证 (Authentication),包括基于 Email 的注册、登录、双因素认证 (2FA) 和账户恢复。 你可以轻松地将 SendGrid 连接为你的 Email 提供商。使用 Logto Email 连接器,你可以在几分钟内完成设置。

要添加 Email 连接器,只需按照以下步骤操作:

  1. 导航到 Console > Connector > Email and SMS connectors
  2. 要添加新的 Email 连接器,点击“设置”按钮并选择“SendGrid”。
  3. 查看你选择的提供商的 README 文档。
  4. 在“参数配置”部分完成配置字段。
  5. 使用 JSON 编辑器自定义 Email 模板。
  6. 通过向你的 电子邮件地址 发送验证码来测试你的配置。

Connector tab

备注:

如果你正在按照就地连接器指南进行操作,可以跳过下一部分。

设置 SendGrid email 连接器

注册 SendGrid 账户

SendGrid 网站创建一个新账户。如果你已经有账户,可以跳过此步骤。

验证发件人

前往 SendGrid 控制台页面并使用你的 SendGrid 账户登录。

发件人表示我们将从哪个地址发送验证码邮件。为了通过 SendGrid 邮件服务器发送邮件,你需要至少验证一个发件人。

SendGrid 控制台页面开始,进入侧边栏的“Settings” -> “Sender Authentication”。

推荐进行域认证,但不是强制的。你可以点击“Authenticate Your Domain”卡片中的“Get started”,并按照接下来的指南将发件人链接并验证到 SendGrid。

通过点击面板中的“Verify a Single Sender”按钮,你现在需要填写一些关键信息来创建一个发件人。按照指南填写所有这些字段,然后点击“Create”按钮。

创建单个发件人后,会向你的发件人邮箱地址发送一封带有验证链接的邮件。进入你的邮箱,找到验证邮件,并通过点击邮件中提供的链接完成单个发件人的验证。现在,你可以使用刚刚验证的发件人通过 SendGrid 连接器发送邮件。

创建 API 密钥

SendGrid 控制台页面开始,进入侧边栏的“Settings” -> “API Keys”。

点击 API Keys 页面右上角的“Create API Key”。输入 API 密钥的名称,并根据你的使用场景自定义“API Key Permission”。在使用此 API 密钥发送邮件之前,需要全局 Full AccessRestricted Access 并对 Mail Send 具有完全访问权限。

在完成 Create API Key 过程后,API 密钥会显示在屏幕上。你应该将此 API 密钥保存在安全的地方,因为这是你唯一能看到它的机会。

配置你的连接器

在“创建 API 密钥”部分中创建的 API Key 填写到 apiKey 字段中。

fromEmailfromName 字段中填写发件人的 From AddressNickname。你可以在 "Sender Management" 页面找到发件人的详细信息。fromName 是可选的,所以你可以跳过填写。

你可以为不同的情况添加多个 SendGrid 邮件连接器模板。以下是添加单个模板的示例:

  • 填写 subject 字段,作为邮件的标题。
  • 用任意字符串类型的内容填写 content 字段。不要忘记保留 {{code}} 占位符用于随机验证码。
  • 根据不同的使用场景填写 usageType 字段,可以是 RegisterSignInForgotPasswordGeneric
  • 根据不同的内容类型填写 type 字段,可以是 text/plaintext/html

为了启用完整的用户流程,需要使用 RegisterSignInForgotPasswordGeneric 的模板。

以下是 SendGrid 连接器模板 JSON 的示例。

[
{
"subject": "<register-template-subject>",
"content": "<Logto: Your verification code is {{code}}. (register template)>",
"usageType": "Register",
"type": "text/plain",
},
{
"subject": "<sign-in-template-subject>",
"content": "<Logto: Your verification code is {{code}}. (sign-in template)>",
"usageType": "SignIn",
"type": "text/plain",
},
{
"subject": "<forgot-password-template-subject>",
"content": "<Logto: Your verification code is {{code}}. (forgot-password template)>",
"usageType": "ForgotPassword",
"type": "text/plain",
},
{
"subject": "<generic-template-subject>",
"content": "<Logto: Your verification code is {{code}}. (generic template)>",
"usageType": "Generic",
"type": "text/plain",
},
]

测试 SendGrid 邮件连接器

你可以输入一个电子邮件地址并点击“Send”来查看设置是否可以在“Save and Done”之前工作。

就是这样。不要忘记 在登录体验中启用连接器

配置类型

名称类型
apiKeystring
fromEmailstring
fromNamestring (可选)
templatesTemplate[]
模板属性类型枚举值
subjectstringN/A
contentstringN/A
usageTypeenum string'Register' | 'SignIn' | 'ForgotPassword' | 'Generic'
typeenum string'text/plain' | 'text/html'

保存你的配置

仔细检查你是否在 Logto 连接器配置区域填写了必要的值。点击“保存并完成”(或“保存更改”),SendGrid 连接器现在应该可用了。

在登录体验中启用 SendGrid 连接器

一旦你成功创建了一个 连接器,你就可以启用基于手机号的无密码登录和注册。

  1. 导航到 Console > 登录体验 > 注册和登录
  2. 设置注册方法(可选):
    1. 选择“电子邮件地址”或“电子邮件或手机号”作为注册标识符。
    2. “注册时验证”被强制启用。你还可以在注册时启用“创建密码”。
  3. 设置登录方法:
    1. 选择 电子邮件地址 作为登录标识符之一。你可以提供多个可用的标识符(电子邮件、手机号和用户名)。
    2. 选择“验证码”和 / 或“密码”作为认证 (Authentication) 因素。
  4. 点击“保存更改”并在“实时预览”中测试。

登录体验选项卡

除了通过 一次性密码进行注册和登录外,你还可以启用密码恢复和基于 的安全验证,以及将 电子邮件地址 关联到个人资料。有关更多详细信息,请参阅 终端用户流程

测试和验证

返回到你的 Flutter 应用。你现在应该可以使用 SendGrid 登录了。享受吧!

进一步阅读

终端用户流程:Logto 提供开箱即用的认证 (Authentication) 流程,包括多因素认证 (MFA) 和企业单点登录 (SSO),以及强大的 API,用于灵活实现账户设置、安全验证和多租户体验。

授权 (Authorization):授权 (Authorization) 定义了用户在被认证 (Authentication) 后可以执行的操作或访问的资源。探索如何保护你的 API 以用于原生和单页应用程序,并实现基于角色的访问控制 (RBAC)。

组织 (Organizations):在多租户 SaaS 和 B2B 应用中特别有效,组织功能支持租户创建、成员管理、组织级 RBAC 和即时供应。

客户 IAM 系列:我们关于客户(或消费者)身份和访问管理的系列博客文章,从 101 到高级主题及更深入的内容。