凭据保险箱:在 Windows 应用商店应用中处理用户和密码的解决方案
如果您还未听说过 Windows 应用商店应用可用的 凭据保险箱,现在就来了解一下相关信息吧。为什么呢?因为不仅可以简化存储和检索用户凭据的任务,它还可以安全地存储用户凭据,并且凭据可以随着用户的 Microsoft 帐户一起“免费”漫游。
假设您有一个应用,该应用会连接到一个服务以访问受保护的资源(如媒体文件、社交网络等)。您的服务需要每个用户的登录信息。因此,您已经在应用内构建了 UI,可以获取用户的用户名和密码,以便使用户登录到服务。这一切都运行流畅无误。
现在您希望为您的用户提供更好的功能,安全地存储他们的登录信息,这样,他们不必在每次使用您的应用时都需要登录一次。输入凭据保险箱。只需几次简单地调用凭据保险箱 API,您可以为用户存储用户名和密码,并可方便地检索用户名和密码,在下次用户打开应用时帮助用户方便地登录。
安全存储
凭据保险箱的一个显著优势就在于可以实现,应用将用户凭据存储在一个安全的位置,当存储在磁盘上时,凭据信息是加密保存的。您当然可以将应用的用户凭据存储在本地存储中的一个文件内,但是以纯文本的形式存储用户凭据会带来潜在的安全漏洞。如果用户的系统因某种方式受到了损害,则用户的用户名和密码就会被轻易地访问和控制。如果使用凭据保险箱来存储用户名和密码,则恶意来源最多就是得到一个加过密的文件。
每个 Windows PC 用户的凭据保险箱都是独一无二的,只有存储凭据的应用才可以访问凭据。也就是说,您只能检索为您的应用存储的凭据。类似地,其他任何应用都不能获取您的应用在保险箱中存储的凭据。
漫游凭据
用户可以获得的另一项好处是,当您使用凭据保险箱存储用户的用户名和密码时,存储的凭据可以随用户的 Microsoft 帐户漫游到他们使用该 Microsoft 帐户的任何其他可信机器。这可以令安全应用对您的用户来说更为方便,因为您的应用可以自动为用户登录 - 无需重新提示用户输入凭据 - 在他们已经利用 Microsoft 帐户安装了您的应用并且有相关 Microsoft 帐户的任何可信电脑上。
其工作方式与域帐户有一点不同。如果存在利用 Microsoft 帐户存储的凭据,并且您将该帐户与域帐户相关联(例如您工作时使用的帐户),则您的凭据将漫游到该域帐户。不过,利用域帐户登录时添加的任何新凭据将不会漫游。这可以确保该域的私有凭据不会在域以外公开。
存储用户凭据
在凭据保险箱中存储用户凭据是一个快捷的两步过程。首先,您使用来自 Windows.Security.Credentials 命名空间中的 PasswordVault 对象获取对凭据保险箱的引用。然后,您创建一个 PasswordCredential 对象,其中包含您的应用的标识符、用户名和密码,并将这些信息传递给 PasswordVault.Add() 方法以便将凭据添加到保险箱。
C#
var vault = new Windows.Security.Credentials.PasswordVault(); vault.Add(new Windows.Security.Credentials.PasswordCredential( "My App", username, password));
JavaScript
var vault = new Windows.Security.Credentials.PasswordVault(); vault.add(new Windows.Security.Credentials.PasswordCredential( "My App", username, password));
检索用户凭据
在拥有对 PasswordVault 对象的引用后,您可以有几种方式来从凭据保险箱检索用户凭据。
- 您可以利用 PasswordVault.RetrieveAll() 方法在保险箱中检索用户为您的应用提供的所有凭据。
- 如果您知道已存储凭据的用户名,则可以利用 PasswordVault.FindAllByUserName() 方法为该用户名检索所有凭据。
- 如果您知道已存储凭据的资源名称,则可以利用 PasswordVault.FindAllByResource() 方法为该资源名称检索所有凭据。
- 最后,如果您既知道凭据的用户名又知道资源名称,则可以利用 PasswordVault.Retrieve() 方法只检索该凭据。
让我们来看一个我们在应用中全局存储资源名称,并且如果我们为用户发现了凭据就会为用户自动登录的示例。如果我们为用户查找发现了多个凭据,我们会询问用户选择一个在登录时使用的默认凭据。
C#
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(); var credentialList = vault.FindAllByResource(resourceName); 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; }
JavaScript
var resourceName = "My App"; var defaultUserName; function 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); } function GetCredentialFromLocker() { var credential = null; var vault = new Windows.Security.Credentials.PasswordVault(); var credentialList = vault.findAllByResource(resourceName); if (credentialList.length > 0) { if (credentialList.length == 1) { credential = credentialList[0]; } else { // When there are multiple usernames, // retrieve the default username. If one doesn’t // exist, display UI to have the user select // a default username. defaultUserName = getDefaultUserNameUI(); credential = vault.retrieve(resourceName, defaultUserName); } } return credential; }
删除用户凭据
在凭据保险箱中删除用户凭据也是一个快捷的两步过程。再一次,您使用来自 Windows.Security.Credentials 命名空间中的 PasswordVault 对象获取对凭据保险箱的引用。然后,您将要删除的凭据传递给 PasswordVault.Remove() 方法。
C#
var vault = new Windows.Security.Credentials.PasswordVault(); vault.Remove(new Windows.Security.Credentials.PasswordCredential( "My App", username, password));
JavaScript
var vault = new Windows.Security.Credentials.PasswordVault(); vault.remove(new Windows.Security.Credentials.PasswordCredential( "My App", username, password));
安全且易用
正如您所见,凭据保险箱是一种易于使用的功能,可以实现验证用户身份以及存储用户凭据以便将来使用这些任务的简化 - 所有这些都是在非常安全的方式下实现。
其他 Windows 8 应用身份验证主题包括 Web 身份验证代理,您可以使用该代理从网站(例如 OAuth)检索身份验证标记,并基于用户的 Microsoft 帐户来个性化您的应用。
有关更多信息,请参阅:
- 管理用户信息 (JavaScript)
- 管理用户信息(使用 C#/VB/C++ 和 XAML 的 Windows 应用商店应用)
- 凭据保险箱示例
- Windows.Security.Credentials
--Windows 开发者内容,高级内容开发者 Doug Rothaus
特别感谢 Yashar Bahman 对本篇博文撰写所作出的贡献。