适用于 Windows 应用的凭据保险箱

本文介绍了 Windows 应用如何使用凭据保险箱安全地存储和检索用户凭据,以及如何使用用户的Microsoft帐户在设备之间漫游。

用于凭据保险箱访问的 Windows 运行时 (WinRT) API 是 Windows 软件开发工具包 (SDK)一部分。 这些 API 已创建用于 通用 Windows 平台 (UWP) 应用,但它们也可以在 WinUI 应用或打包的桌面应用中使用,包括 WPF 和Windows 窗体。 有关在 Windows 桌面应用中使用 WinRT API 的详细信息,请参阅在桌面应用中调用Windows 运行时 API。

示例方案的概述

例如,你有一个连接到服务以访问受保护资源(如媒体文件或社交网络)的应用。 你的服务需要每位用户的登录信息。 你已将 UI 内置到应用中,用于获取用户的用户名和密码,然后使用该 UI 将用户登录到服务中。 使用保险箱 API 可为用户存储用户名和密码,并在他们下次打开应用时轻松地检索它们并自动使用户登录(不论他们在什么设备上)。

存储在凭据保险箱中的用户凭据不会过期,不受 ApplicationData.RoamingStorageQuota 的影响,由于传统漫游数据不活动,因此不会清除。 但是,在凭据保险箱中,每个应用最多只能存储 20 个凭据。

凭据保险箱对于域帐户的工作方式略有不同。 如果有凭据与 Microsoft 帐户一起存储,并且将该帐户与域帐户关联(如作时使用的帐户),凭据将漫游至该域帐户。 但是,任何在使用域帐户登录时添加的新凭据不会漫游。 这可确保域的专用凭据不会在域外部公开。

存储用户凭据

  1. 使用来自 Windows.Security.Credentials 命名空间的 PasswordVault 对象获取对凭据保险箱的引用。
  2. 创建包含你的应用的标识符、用户名和密码的 PasswordCredential 对象,并将该对象传递至 PasswordVault.Add 方法以将凭据添加到保险箱。
var vault = new Windows.Security.Credentials.PasswordVault();
vault.Add(new Windows.Security.Credentials.PasswordCredential(
    "My App", username, password));

检索用户凭据

在你拥有对 PasswordVault 对象的引用之后,你有多个选项从凭据保险箱检索用户凭据。

让我们来查看一个示例,在此示例中我们已在一个应用中全局存储了资源名,并且,如果找到了它们的凭据,我们将使用户自动登录。 如果我们找到了同一个用户的多个凭据,我们将要求用户选择一个默认凭据以在登录时使用。

private string resourceName = "My App";
private string defaultUserName;

private void Login()
{
    var loginCredential = GetCredentialFromLocker();

    if (loginCredential != null)
    {
        // There is a credential stored in the locker.
        // Populate the Password property of the credential
        // for automatic login.
        loginCredential.RetrievePassword();
    }
    else
    {
        // There is no credential stored in the locker.
        // Display UI to get user credentials.
        loginCredential = GetLoginCredentialUI();
    }

    // Log the user in.
    ServerLogin(loginCredential.UserName, loginCredential.Password);
}

private Windows.Security.Credentials.PasswordCredential GetCredentialFromLocker()
{
    Windows.Security.Credentials.PasswordCredential credential = null;

    var vault = new Windows.Security.Credentials.PasswordVault();

    IReadOnlyList<PasswordCredential> credentialList = null;

    try
    {
        credentialList = vault.FindAllByResource(resourceName);
    }
    catch(Exception)
    {
        return null;
    }

    if (credentialList.Count > 0)
    {
        if (credentialList.Count == 1)
        {
            credential = credentialList[0];
        }
        else
        {
            // When there are multiple usernames,
            // retrieve the default username. If one doesn't
            // exist, then display UI to have the user select
            // a default username.
            defaultUserName = GetDefaultUserNameUI();

            credential = vault.Retrieve(resourceName, defaultUserName);
        }
    }

    return credential;
}

删除用户凭据

在凭据保险箱中删除用户凭据是一个快捷的两步式过程。

  1. 使用来自 Windows.Security.Credentials 命名空间的 PasswordVault 对象获取对凭据保险箱的引用。
  2. 将希望删除的凭据传递至 PasswordVault.Remove 方法。
var vault = new Windows.Security.Credentials.PasswordVault();
vault.Remove(new Windows.Security.Credentials.PasswordCredential(
    "My App", username, password));

最佳实践

将凭据保险箱仅用于存储密码,而不要将其用于存储较大的数据 blob。

仅当满足以下条件时才将密码保存在凭据保险箱中:

  • 用户已成功登录。
  • 用户已选择保存密码。

永远不要使用应用数据或漫游设置在纯文本中存储凭据。