自定义函数身份验证
在此页面上
Overview
自定义函数身份验证提供程序允许您使用无服务器函数定义自定义身份验证流程。可以使用该提供程序实施您自己的用户身份验证逻辑或集成外部身份验证系统。
何时使用自定义函数身份验证
自定义函数身份验证是身份验证中最灵活的形式。但是,这还需要您自己手动定义和配置身份验证流程。
在定义自定义函数提供程序之前,请考虑是否可以改用内置身份验证提供程序。
在以下情况下,请考虑在应用程序中使用自定义函数提供程序:
您希望使用没有内置提供程序的外部身份验证服务。如果该服务使用 JSON Web 令牌,请考虑改为创建自定义 JWT 提供程序。
您希望自定义身份验证过程,而不是内置提供商中提供的身份验证过程。例如,您可以使用服务发送自定义确认电子邮件,而不是默认的电子邮件/密码提供商电子邮件。
重要
下图显示了自定义函数登录流程:
身份验证函数
身份验证函数是一个 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 不同,后者是作为用户对象的 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}`); }
设置自定义函数提供程序
您可以使用任何受支持的部署方法配置自定义函数身份验证。
定义身份验证函数
提供商使用普通函数来处理身份验证。该函数应返回一个唯一的外部 ID 字符串来标识用户。
要定义新的身份验证函数,请执行以下操作:
单击 Function(添加数据)下拉列表并选择 New Function(插入文档)。
输入函数名称。此名称在应用程序的所有函数中必须是唯一的。
在函数编辑器中定义源代码。
单击 Save
定义身份验证函数
提供商使用普通函数来处理身份验证。 该函数应返回一个唯一的外部 ID 字符串来标识用户。 用户。
将身份验证函数代码保存在functions
目录中。
touch functions/handleCustomFunctionAuthentication.js
添加提供程序配置文件
要启用和配置自定义函数身份验证提供者,请在/auth/providers.json
中为其定义一个配置对象。
自定义函数提供商配置具有以下形式:
{ "custom-function": { "name": "custom-function", "type": "custom-function", "config": { "authFunctionName": "<Authentication Function Name>" }, "disabled": false } }
配置自定义用户数据
您可以将 MongoDB Atlas 集合中的自定义数据与应用程序中的用户帐户关联起来。如果您经常需要访问用户的数据,但又不需要使用自定义函数提供程序,这将很有帮助。
用户的自定义数据文档可以包含任何数据。对于使用自定义函数提供商的应用,我们建议存储用户的内部用户帐户 ID 及其外部 ID。
例如,您可以使用以下格式:
{ "_id": "<Generated ObjectId>", "user_id": "<Internal User ID>", "external_id": "<External User ID>" }
您可以使用以下方法为自定义函数提供商用户创建自定义用户文档:
为关联集群中的集合配置自定义用户数据。用户 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 } 配置自定义函数身份验证提供程序,并从身份验证函数中返回唯一的外部用户 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; }; 设置一个身份验证触发器,以侦听来自
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(), }); };
从 Realm SDK 登录
要从客户端应用程序登录,请使用包含登录有效负载数据的自定义函数档案。
例如,请参阅特定 SDK 的文档: