Docs 菜单
Docs 主页
/ /
Atlas App Services
/ /

自定义函数身份验证

在此页面上

  • 概述
  • 何时使用自定义函数身份验证
  • 身份验证函数
  • 接收自定义凭证有效负载
  • 返回经过身份验证的用户 ID
  • 由于身份验证失败而引发错误
  • 设置自定义函数提供程序
  • 启用自定义函数提供程序
  • 定义身份验证函数
  • 部署更新的应用程序
  • 拉取最新版本的应用程序
  • 定义身份验证函数
  • 添加提供程序配置文件
  • 部署更新的应用程序
  • 配置自定义用户数据
  • 从 Realm SDK 登录

自定义函数身份验证提供程序允许您使用无服务器函数定义自定义身份验证流程。可以使用该提供程序实施您自己的用户身份验证逻辑或集成外部身份验证系统。

自定义函数身份验证是身份验证中最灵活的形式。但是,这还需要您自己手动定义和配置身份验证流程。

在定义自定义函数提供程序之前,请考虑是否可以改用内置身份验证提供程序

在以下情况下,请考虑在应用程序中使用自定义函数提供程序:

  • 您希望使用没有内置提供程序的外部身份验证服务。如果该服务使用 JSON Web 令牌,请考虑改为创建自定义 JWT 提供程序。

  • 您希望自定义身份验证过程,而不是内置提供商中提供的身份验证过程。例如,您可以使用服务发送自定义确认电子邮件,而不是默认的电子邮件/密码提供商电子邮件。

重要

Atlas App Services 不会对自定义函数提供商执行任何数据验证或身份验证检查。

Make sure that you validate incoming data and that your authentication system performs appropriate authentication checks, such as requiring a password, two-factor authentication, or a single sign-on token.

下图显示了自定义函数登录流程:

自定义函数身份验证流程图

身份验证函数是一个 JavaScript 函数,用于保存自定义用户身份验证代码。每当用户通过自定义函数提供商登录时,它就会运行。

该函数将登录时提供的数据(例如用户名和密码或访问令牌)映射到外部身份验证系统中唯一标识用户的字符串。例如,您可以使用提供的数据通过 HTTP 或使用 npm 中的包登录到外部服务。

exports = async function (payload) {
// 1. Parse the `payload` object, which holds data from the
// FunctionCredential sent by the SDK.
const { username, password } = payload;
// 2. Create a new user or log in an existing user in the external
// authentication service.
// You can use a client library from npm
const auth = require("fake-auth-service");
const user = await auth.login({ username, password });
// Or you can communicate directly over HTTP
const userFromHttp = await context.http.post({
url: "https://example.com/auth/login",
headers: {
Authorization: ["Basic bmlja0BleGFtcGxlLmNvbTpQYTU1dzByZA=="],
},
body: JSON.stringify({ username, password }),
});
// 3. Return a unique identifier for the user. Typically this is the
// user's ID in the external authentication system or the _id of a
// stored MongoDB document that describes them.
//
// !!! This is NOT the user's internal account ID for your app !!!
return user.id;
};

传递给函数的 payload 对象包含客户端应用程序中的自定义函数提供程序凭证包含的数据。函数接受从客户端应用程序中提供的任何值,因此,实际字段名称和值取决于您的实施。

有关如何使用 Realm SDK 创建自定义凭证 payload 对象的示例,请参阅每个 SDK 的文档:

如果身份验证成功,该函数应返回用户的唯一字符串标识符。例如,您可以返回外部身份验证系统使用的用户 ID 值。这是用户的外部 ID,提供程序使用它将自定义系统映射到应用程序的内部用户帐户。

重要

用户的外部 ID 与用户的内部帐户 ID 不同,后者是作为用户对象的 id 字段公开的。您可以使用表达式中的 %%user.id、函数中的 context.user.id 以及 SDK 中的 User.id 属性访问用户的内部 ID。

如果现有用户已与外部 ID 关联,则提供商将该用户登录。

如果提供者没有给定外部 ID 的记录,它将创建一个新的用户帐户,添加自定义函数提供者身份,然后登录新用户。

自定义函数提供程序的身份对象存储在用户对象中,类似于以下内容:

{
"id": "<Internal User Account ID>",
"identities": [
{
"providerType": "custom-function",
"id": "<External User ID>",
}
]
}

例子

身份验证函数应返回一个唯一的外部 ID,作为字符串:

return "5f650356a8631da45dd4784c"

您还可以返回一个包含外部 ID 以作为 id 值的对象:

return { "id": "5f650356a8631da45dd4784c" }

如果要为用户定义显示名称,请在返回的对象的 name 字段中定义该名称:

return {
"id": "5f650356a8631da45dd4784c",
"name": "James Bond"
}

如果用户提供的凭证无效,或者函数由于其他原因无法对用户进行身份验证,则会引发错误并显示描述性消息。这会返回 401 - Unauthorized 错误,并将消息附加到 SDK 中。

const auth = require("some-external-auth-system");
try {
const user = await auth.login(payload);
return user.id;
} catch (err) {
throw new Error(`Authentication failed with reason: ${err.message}`);
}

您可以使用任何受支持的部署方法配置自定义函数身份验证。

1

要启用提供商,请执行以下操作:

  1. 单击左侧导航菜单中的 App Users(应用用户)。

  2. 选择 Providers 标签页。

  3. 单击 Custom Function Authentication(连接)。

  4. 在提供商配置屏幕上,将 Provider Enabled 开关设置为 On

App Services 用户界面中的身份验证提供程序列表,其中突出显示了自定义函数提供程序。
点击放大
2

提供商使用普通函数来处理身份验证。该函数应返回一个唯一的外部 ID 字符串来标识用户。

要定义新的身份验证函数,请执行以下操作:

  1. 单击 Function(添加数据)下拉列表并选择 New Function(插入文档)。

  2. 输入函数名称。此名称在应用程序的所有函数中必须是唯一的。

  3. 在函数编辑器中定义源代码。

  4. 单击 Save

App Services 用户界面中的函数选择下拉列表。
点击放大
3

要使自定义函数身份验证可供客户端应用程序使用,请部署应用程序。

  1. 单击左侧导航菜单中的 Deploy

  2. 在部署历史记录表中找到草稿,然后单击 Review & Deploy Changes

  3. 查看更改的差异,然后单击 Deploy

1

要提取最新版本应用的本地副本,请运行以下命令:

appservices pull --remote="<Your App ID>"

提示

您还可以从 App Services 用户界面的Deploy > Export App屏幕下载应用程序配置文件的副本。

2

提供商使用普通函数来处理身份验证。 该函数应返回一个唯一的外部 ID 字符串来标识用户。 用户。

身份验证函数代码保存在functions目录中。

touch functions/handleCustomFunctionAuthentication.js
3

要启用和配置自定义函数身份验证提供者,请在/auth/providers.json中为其定义一个配置对象

自定义函数提供商配置具有以下形式:

/auth/providers.json
{
"custom-function": {
"name": "custom-function",
"type": "custom-function",
"config": {
"authFunctionName": "<Authentication Function Name>"
},
"disabled": false
}
}
4

创建身份验证函数并配置提供商后,您可以将更新配置推送到远程应用程序。App Services CLI 在推送时立即部署新模式。

appservices push --remote="<Your App ID>"

您可以将 MongoDB Atlas 集合中的自定义数据与应用程序中的用户帐户关联起来。如果您经常需要访问用户的数据,但又不需要使用自定义函数提供程序,这将很有帮助。

用户的自定义数据文档可以包含任何数据。对于使用自定义函数提供商的应用,我们建议存储用户的内部用户帐户 ID 及其外部 ID。

例如,您可以使用以下格式:

{
"_id": "<Generated ObjectId>",
"user_id": "<Internal User ID>",
"external_id": "<External User ID>"
}

您可以使用以下方法为自定义函数提供商用户创建自定义用户文档:

  1. 为关联集群中的集合配置自定义用户数据。用户 ID 字段存储用户的内部帐户 ID。

    /auth/custom_user_data.json
    {
    "mongo_service_name": "mongodb-atlas",
    "database_name": "myApp",
    "collection_name": "users",
    "user_id_field": "user_id",
    "enabled": true
    }
  2. 配置自定义函数身份验证提供程序,并从身份验证函数中返回唯一的外部用户 ID。App Services 将该 ID 存储在用户的 custom-function 身份的 id 字段中。

    exports = async function handleCustomFunctionAuth(payload) {
    const auth = require("some-external-auth-system");
    const user = await auth.login(payload);
    return user.id;
    };
  3. 设置一个身份验证触发器,以侦听来自 custom-function 提供程序的 CREATE 事件。在触发器函数中,将一个新文档添加到自定义用户数据集合中,其中包括用户的内部 ID 和外部 ID。

    exports = async function onNewCustomFunctionUser({ user }) {
    // This is the user's internal account ID that was generated by your app
    const internalId = user.id;
    // This is the external ID returned from the authentication function
    const customFunctionIdentity = user.identities.find((id) => {
    return id.provider_type === "custom-function";
    });
    const externalId = customFunctionIdentity.id;
    // Create a custom user data document for the user
    const mdb = context.services.get("mongodb-atlas");
    const users = mdb.db("myApp").collection("users");
    return await users.insertOne({
    // Include both the internal ID and external ID
    user_id: internalId,
    external_id: externalId,
    // Add any other data you want to include
    created_at: new Date(),
    });
    };

要从客户端应用程序登录,请使用包含登录有效负载数据的自定义函数档案。

例如,请参阅特定 SDK 的文档:

后退

Apple ID

来年

自定义 JWT