用户登录

要让用户登录,请从浏览器的密码管理器中检索凭据,并使用这些凭据自动登录用户。对于拥有多个帐户的用户,让他们只需轻点一下帐户选择器即可选择帐户。

自动登录

自动登录可以在您网站的任何位置发生;不仅是首页,其他叶子页面也是如此。当用户通过搜索引擎访问您网站中的各种页面时,这非常有用。

要启用自动登录

  1. 获取凭据信息。
  2. 验证用户身份。
  3. 更新 UI 或转到个性化页面。

获取凭据信息

浏览器支持

  • Chrome: 51.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

来源

要获取凭据信息,请调用 navigator.credentials.get()。 通过提供 passwordfederated 来指定要请求的凭据类型。

始终对自动登录使用 mediation: 'silent',这样,如果用户出现以下情况,您可以轻松地取消该过程

  • 没有存储凭据。
  • 存储了多个凭据。
  • 已退出登录。

在获取凭据之前,请不要忘记检查用户是否已登录

if (window.PasswordCredential || window.FederatedCredential) {
  if (!user.isSignedIn()) {
    navigator.credentials.get({
      password: true,
      federated: {
        providers: ['https://127.0.0.1'],
      },
      mediation: 'silent',
    });
    // ...
  }
}

navigator.credentials.get() 返回的 Promise 会解析为凭据对象或 null。 要确定它是 PasswordCredential 还是 FederatedCredential,只需查看对象的 .type 属性,该属性将为 passwordfederated

如果 .typefederated,则 .provider 属性是一个字符串,表示身份提供商。

验证用户身份

获得凭据后,根据凭据类型(passwordfederated)运行身份验证流程

    }).then(c => {
     if (c) {
       switch (c.type) {
         case 'password':
           return sendRequest(c);
           break;
         case 'federated':
           return gSignIn(c);
           break;
       }
     } else {
       return Promise.resolve();
     }

当 Promise 解析时,检查您是否收到了凭据对象。 如果没有,则表示自动登录无法发生。 静默取消自动登录过程。

更新 UI

如果身份验证成功,请更新 UI 或将用户转发到个性化页面

    }).then(profile => {
     if (profile) {
       updateUI(profile);
     }

不要忘记显示身份验证错误消息

为避免用户感到困惑,用户应在获取凭据对象时看到一个蓝色 Toast 消息,显示“正在登录”

Blue toast showing user is signing in.

一个重要的提示:如果您成功获取了凭据对象但未能验证用户身份,则应显示错误消息

        }).catch(error => {
          showError('Sign-in Failed');
        });
      }
    }

完整代码示例

if (window.PasswordCredential || window.FederatedCredential) {
  if (!user.isSignedIn()) {
    navigator.credentials
      .get({
        password: true,
        federated: {
          providers: ['https://127.0.0.1'],
        },
        mediation: 'silent',
      })
      .then((c) => {
        if (c) {
          switch (c.type) {
            case 'password':
              return sendRequest(c);
              break;
            case 'federated':
              return gSignIn(c);
              break;
          }
        } else {
          return Promise.resolve();
        }
      })
      .then((profile) => {
        if (profile) {
          updateUI(profile);
        }
      })
      .catch((error) => {
        showError('Sign-in Failed');
      });
  }
}

通过帐户选择器登录

如果用户需要媒介,或者有多个帐户,请使用帐户选择器让用户登录,跳过普通的登录表单,例如

Google account chooser showing multiple accounts.

通过帐户选择器登录的步骤与自动登录中的步骤相同,但需要额外调用以显示帐户选择器作为获取凭据信息的一部分

  1. 获取凭据信息并显示帐户选择器。
  2. 验证用户身份.
  3. 更新 UI 或转到个性化页面.

获取凭据信息并显示帐户选择器

响应已定义的用户操作(例如,当用户点击“登录”按钮时)显示帐户选择器。 调用 navigator.credentials.get(),并添加 mediation: 'optional'mediation: 'required' 以显示帐户选择器。

mediationrequired 时,始终会向用户显示帐户选择器以进行登录。 此选项允许拥有多个帐户的用户轻松地在帐户之间切换。 当 mediationoptional 时,在调用 navigator.credentials.preventSilentAccess() 后,会明确向用户显示帐户选择器以进行登录。 这通常是为了确保在用户选择退出或取消注册后不会发生自动登录。

显示 mediation: 'optional' 的示例

    var signin = document.querySelector('#signin');
    signin.addEventListener('click', e => {
     if (window.PasswordCredential || window.FederatedCredential) {
       navigator.credentials.get({
         password: true,
         federated: {
           providers: [
             'https://127.0.0.1'
           ]
         },
         mediation: 'optional'
       }).then(c => {

用户选择帐户后,Promise 将解析为凭据。 如果用户取消帐户选择器,或者没有存储凭据,则 Promise 将解析为 null。 在这种情况下,回退到登录表单体验。

不要忘记回退到登录表单

出于以下任何原因,您都应回退到登录表单

  • 未存储凭据。
  • 用户在未选择帐户的情况下关闭了帐户选择器。
  • API 不可用。
    }).then(profile => {
        if (profile) {
          updateUI(profile);
        } else {
          location.href = '/signin';
        }
    }).catch(error => {
        location.href = '/signin';
    });

完整代码示例

var signin = document.querySelector('#signin');
signin.addEventListener('click', (e) => {
  if (window.PasswordCredential || window.FederatedCredential) {
    navigator.credentials
      .get({
        password: true,
        federated: {
          providers: ['https://127.0.0.1'],
        },
        mediation: 'optional',
      })
      .then((c) => {
        if (c) {
          switch (c.type) {
            case 'password':
              return sendRequest(c);
              break;
            case 'federated':
              return gSignIn(c);
              break;
          }
        } else {
          return Promise.resolve();
        }
      })
      .then((profile) => {
        if (profile) {
          updateUI(profile);
        } else {
          location.href = '/signin';
        }
      })
      .catch((error) => {
        location.href = '/signin';
      });
  }
});

联合登录

联合登录让用户只需轻点一下即可登录,而无需记住您网站的其他登录详细信息。

要实施联合登录

  1. 使用第三方身份验证用户身份。
  2. 存储身份信息。
  3. 更新 UI 或转到个性化页面(与自动登录中的相同)。

使用第三方身份验证用户身份

当用户点击联合登录按钮时,使用 FederatedCredential 运行特定的身份提供商身份验证流程。

浏览器支持

  • Chrome: 51.
  • Edge: 79.
  • Firefox:不支持。
  • Safari:不支持。

来源

例如,如果提供商是 Google,请使用Google 登录 JavaScript 库

navigator.credentials
  .get({
    password: true,
    mediation: 'optional',
    federated: {
      providers: ['https://account.google.com'],
    },
  })
  .then(function (cred) {
    if (cred) {
      // Instantiate an auth object
      var auth2 = gapi.auth2.getAuthInstance();

      // Is this user already signed in?
      if (auth2.isSignedIn.get()) {
        var googleUser = auth2.currentUser.get();

        // Same user as in the credential object?
        if (googleUser.getBasicProfile().getEmail() === cred.id) {
          // Continue with the signed-in user.
          return Promise.resolve(googleUser);
        }
      }

      // Otherwise, run a new authentication flow.
      return auth2.signIn({
        login_hint: id || '',
      });
    }
  });

Google 登录会生成 ID 令牌作为身份验证证明。

通常,联合登录构建在标准协议(如 OpenID ConnectOAuth)之上。 要了解如何使用联合帐户进行身份验证,请参阅各个联合身份提供商的文档。 热门示例包括

存储身份信息

身份验证完成后,您可以存储身份信息。 您将在此处存储的信息是身份提供商的 id 和表示身份提供商的提供商字符串(nameiconURL 是可选的)。 在凭据管理规范中了解有关此信息的更多信息。

要存储联合帐户详细信息,请使用用户的标识符和提供商的标识符实例化新的 FederatedCredential 对象。 然后调用 navigator.credentials.store() 以存储身份信息。

成功联合后,同步或异步实例化 FederatedCredential

同步方法示例

// Create credential object synchronously.
var cred = new FederatedCredential({
  id: id, // id in IdP
  provider: 'https://account.google.com', // A string representing IdP
  name: name, // name in IdP
  iconURL: iconUrl, // Profile image url
});

异步方法示例

// Create credential object asynchronously.
var cred = await navigator.credentials.create({
  federated: {
    id: id,
    provider: 'https://127.0.0.1',
    name: name,
    iconURL: iconUrl,
  },
});

然后存储凭据对象

// Store it
navigator.credentials.store(cred).then(function () {
  // continuation
});

退出登录

当用户点击退出登录按钮时,请让用户退出登录。 首先终止会话,然后关闭未来访问的自动登录。(如何终止会话完全取决于您。)

关闭未来访问的自动登录

调用 navigator.credentials.preventSilentAccess()

signoutUser();
if (navigator.credentials && navigator.credentials.preventSilentAccess) {
  navigator.credentials.preventSilentAccess();
}

这将确保在用户下次启用自动登录之前不会发生自动登录。 要恢复自动登录,用户可以选择通过从帐户选择器中选择他们希望登录的帐户来有意登录。 然后,用户将始终保持登录状态,直到他们明确退出登录。

反馈