跳至内容

accounts-2fa

此包允许您为用户提供一种在其账户上启用 2FA 的方法,可以使用身份验证器应用程序(例如 Google Authenticator 或 1Password)。当用户在您的应用程序上登录时,他们将能够生成一个新的二维码并在他们首选的应用程序上读取此代码。之后,他们将开始接收他们的代码。然后,他们可以在您的应用程序上完成启用 2FA,并且每次他们尝试登录到您的应用程序时,您都可以将他们重定向到一个可以提供他们从身份验证器收到的代码的地方。

为了提供与所有其他实现 TOTP 的身份验证器应用程序和服务完全兼容的代码,此包使用 node-2fa,它基于 notp 工作,**该**包实现了 TOTP (RFC 6238)(身份验证器标准),它基于 HOTP (RFC 4226)。

此包旨在与 accounts-passwordaccounts-passwordless 一起使用,因此,如果您在项目中没有这两个包中的任何一个,则需要添加其中一个。将来,我们希望能够将此包与其他登录方法(我们的 oauth 方法(Google、GitHub 等...))一起使用。

2FA 激活流程

为了启用 2FA,第一步是生成一个二维码,以便用户可以在身份验证器应用程序中扫描它并开始接收代码。

Accounts.generate2faActivationQrCode

仅限客户端

摘要

生成 SVG 二维码并在用户处保存密钥

参数

源代码
名称类型描述必需
appName字符串

这是您的应用程序的名称,将在用户扫描二维码时显示。

callback函数

在失败时使用单个 Error 参数调用。或者,在成功时,使用包含 SVG 格式的二维码 (svg)、二维码密钥 (secret) 和 URI 的对象调用,以便用户无需读取二维码即可手动激活 2FA (uri)。

js
import { Accounts } from "meteor/accounts-base";


const result = Accounts.generate2faActivationQrCode();
  "appName",
() => {},
);

接收一个 appName,它是您的应用程序的名称,将在用户扫描二维码时显示。此外,在成功时使用 SVG 格式的二维码、二维码密钥和可用于在身份验证器应用程序中激活 2FA 的 URI 调用回调,或在失败时使用单个 Error 参数调用回调。

在成功时,此函数还会将一个对象添加到已登录用户的 services 对象中,其中包含二维码密钥

js
services: {
  ...
  twoFactorAuthentication: {
    secret: "***"
  }
}

这是一个关于如何调用此函数的示例

js
import { Buffer } from "buffer";
import { Accounts } from 'meteor/accounts-base';


// component
const [qrCode, setQrCode] = useState(null);


<button
  onClick={() => {
    Accounts.generate2faActivationQrCode("My app name", (err, result) => {
      if (err) {console.error("...", err);return;}
      const { svg, secret, uri } = result;
      /*
        the svg can be converted to base64, then be used like:
         <img
            width="200"
            src={`data:image/svg+xml;base64,${qrCode}`}
         />
      */
      setQrCode(Buffer.from(svg).toString('base64'));
    })
  }}
>
  Generate a new code
</button>

此方法可能会失败并抛出以下错误

  • “2FA 已激活。您需要先禁用 2FA,然后才能尝试生成新的激活码 [2fa-activated]”如果尝试在用户已启用 2FA 时生成激活。

此时,2FA 尚未激活。现在用户可以访问其身份验证器应用程序生成的代码,您可以调用函数 Accounts.enableUser2fa

Accounts.enableUser2fa

仅限客户端

摘要

启用用户 2FA

参数

源代码
名称类型描述必需
code字符串

从身份验证器应用程序接收的代码。

callback函数

可选回调。在成功时不带参数调用,或在失败时使用单个 Error 参数调用。

js
import { Accounts } from "meteor/accounts-base";


const result = Accounts.enableUser2fa();
  "code",
() => {}, // this param is optional
);

它应该使用用户在读取二维码后从身份验证器应用程序接收的代码调用。回调在失败时使用单个 Error 参数调用。如果提供的代码正确,则 type 将添加到用户的 twoFactorAuthentication 对象中,现在 2FA 被认为已启用

js
services: {
  ...
  twoFactorAuthentication: {
    type: "otp",
    secret: "***",
  }
}

要验证用户是否启用了 2FA,您可以调用函数 Accounts.has2faEnabled

Accounts.has2faEnabled

仅限客户端

摘要

验证已登录的用户是否启用了 2FA

参数

源代码
名称类型描述必需
callback函数

在成功时使用布尔值调用,指示用户是否启用了 2FA,或在失败时使用单个 Error 参数调用。

js
import { Accounts } from "meteor/accounts-base";


const result = Accounts.has2faEnabled();
  () => {}
);

此函数必须在用户登录时调用。

禁用 2FA

要为用户禁用 2FA,请使用此方法

Accounts.disableUser2fa

仅限客户端

摘要

禁用用户 2FA

参数

源代码
名称类型描述必需
callback函数

可选回调。在成功时不带参数调用,或在失败时使用单个 Error 参数调用。

js
import { Accounts } from "meteor/accounts-base";


const result = Accounts.disableUser2fa();
  () => {}
);

要调用此函数,用户必须已登录。

使用 2FA 登录

现在您有了一种允许用户在其账户上启用 2FA 的方法,您可以基于此创建登录流程。

如本指南开头所述,此包目前正在与另外两个包一起使用:accounts-passwordaccounts-passwordless。下面解释了如何将此包与它们一起使用。

与 accounts-password 结合使用

当调用函数 Meteor.loginWithPassword 时,如果为用户启用了 2FA,则会向回调返回错误,以便您可以将用户重定向到可以提供代码的位置。

例如

js
<button
  onClick={() => {
    Meteor.loginWithPassword(username, password, (error) => {
      if (error) {
        if (error.error === "no-2fa-code") {
          // send user to a page or show a component
          // where they can provide a 2FA code
          setShouldAskCode(true);
          return;
        }
        console.error("Error trying to log in (user without 2fa)", error);
      }
    });
  }}
>
  Login
</button>

如果未启用 2FA,则用户将正常登录。

您现在需要调用的函数以允许用户登录是 Meteor.loginWithPasswordAnd2faCode

Meteor.loginWithPasswordAnd2faCode

仅限客户端

摘要

使用密码和令牌登录用户。

参数

源代码
名称类型描述必需
selector对象或字符串

可以是解释为用户名或电子邮件的字符串;或者是一个具有单个键的对象:emailusernameid。用户名或电子邮件不区分大小写匹配。

password字符串

用户的密码。

token字符串

用户身份验证器应用程序提供的令牌。

callback函数

可选回调。在成功时不带参数调用,或在失败时使用单个 Error 参数调用。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.loginWithPasswordAnd2faCode();
  selector,
"password",

"token",

() => {}, // this param is optional
);

现在您将能够从用户那里接收代码,此函数将验证代码是否有效。如果是,则用户将登录。

因此,此函数的调用应该如下所示

js
<button
  onClick={() => {
    Meteor.loginWithPasswordAnd2faCode(username, password, code, (error) => {
      if (error) {
        console.error("Error trying to log in (user with 2fa)", error);
      }
    });
  }}
>
  Validate and log in
</button>

此方法可能会失败并抛出以下错误之一

  • “必须提供 2FA 代码 [no-2fa-code]”如果没有提供 2FA 代码。
  • “无效的 2FA 代码 [invalid-2fa-code]”如果提供的 2FA 代码无效。

与 accounts-passwordless 结合使用

遵循先前包的相同逻辑,如果启用了 2FA,则会向函数 Meteor.passwordlessLoginWithToken 的回调返回错误,然后您可以将用户重定向到可以提供代码的位置。

这是一个示例

js
<button
  onClick={() => {
    // logging in just with token
    Meteor.passwordlessLoginWithToken(email, token, (error) => {
      if (error) {
        if (error.error === "no-2fa-code") {
          // send user to a page or show a component
          // where they can provide a 2FA code
          setShouldAskCode(true);
          return;
        }
        console.error("Error verifying token", error);
      }
    });
  }}
>
  Validate token
</button>

现在您可以调用函数 Meteor.passwordlessLoginWithTokenAnd2faCode,它将允许您提供选择器、令牌和 2FA 代码

Meteor.passwordlessLoginWithTokenAnd2faCode

仅限客户端

摘要

使用一次性令牌登录用户。

参数

源代码
名称类型描述必需
selector对象或字符串

用户名、电子邮件或自定义选择器以识别用户。

token字符串

服务器生成的一次性令牌

code字符串

由用户的身份验证器应用程序生成

callback函数

可选回调。在成功时不带参数调用,或在失败时使用单个 Error 参数调用。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.passwordlessLoginWithTokenAnd2faCode();
  selector,
"token",

"code",

() => {}, // this param is optional
);

此方法可能会失败并抛出以下错误之一

  • “必须提供 2FA 代码 [no-2fa-code]”如果没有提供 2FA 代码。
  • “无效的 2FA 代码 [invalid-2fa-code]”如果提供的 2FA 代码无效。

将身份验证包与 accounts-2fa 集成

要将此包与任何其他现有的登录方法集成,需要执行以下两个步骤

1 - 对于客户端,从您当前的登录方法创建一个新方法。例如,从方法 Meteor.loginWithPassword 中,我们创建了一个名为 Meteor.loginWithPasswordAnd2faCode 的新方法,它们之间的唯一区别是后者接收一个额外的参数,即 2FA 代码,但在服务器端我们调用相同的函数。

2 - 对于服务器,在用于登录用户的函数内部,您需要验证函数Accounts._check2faEnabled是否存在,如果存在,则调用它并提供您想要检查其是否启用了 2FA 的用户对象。如果这两个语句中的任何一个为假,则继续执行登录流程。此函数仅在将包accounts-2fa添加到项目中时才存在。

如果这两个语句都为真,并且登录验证成功,则您需要验证是否提供了验证码:如果没有提供,则抛出错误;如果提供了,则通过调用函数Accounts._isTokenValid验证验证码是否有效。如果Accounts._isTokenValid返回 false,则抛出错误。

以下是一个示例

js
const result = validateLogin();
if (!result.error && Accounts._check2faEnabled?.(user)) {
  if (!code) {
    Accounts._handleError("2FA code must be informed.");
  }
  if (
    !Accounts._isTokenValid(user.services.twoFactorAuthentication.secret, code)
  ) {
    Accounts._handleError("Invalid 2FA code.");
  }
}

return result;