使用C#从Windows凭据存储中检索凭据

我只想查询凭据存储(或在Win8中调用的Vault)并获取登录数据。 在这种情况下,MSDN真的没有用,我也不想要任何C ++ pInvoke方法。

我知道这里曾经问过几次类似的问题,但这些解决方案都不适合我的情况。 我不使用Metro App编程,所以像PasswordVault这样的东西(看起来不可用)。 我只是创建一个简单的C#WPF桌面应用程序。

理想情况下它应该适用于多个Windows版本,但首选Win8。

更具体地说,我想查询来自CRM插件的存储数据,以便自动让我的应用程序登录到CRM服务器,而无需用户请求他的凭据。 这意味着,如果这是可能的……

那么如何访问Windows凭据存储?

有一个我一直在使用的Nuget图书馆,名为CredentialManagement http://nuget.org/packages/CredentialManagement/

用法非常简单。 我把它包裹了一点,但可能不需要:

 public static class CredentialUtil { public static UserPass GetCredential(string target) { var cm = new Credential {Target = target}; if (!cm.Load()) { return null; } //UserPass is just a class with two string properties for user and pass return new UserPass(cm.Username, cm.Password); } public static bool SetCredentials( string target, string username, string password, PersistanceType persistenceType) { return new Credential {Target = target, Username = username, Password = password, PersistanceType = persistenceType}.Save(); } public static bool RemoveCredentials(string target) { return new Credential { Target = target }.Delete(); } } 

样品用法:

 CredentialUtil.SetCredentials("FOO", "john", "1234", PersistanceType.LocalComputer); var userpass = CredentialUtil.GetCredential("FOO"); Console.WriteLine($"User: {userpass.Username} Password: {userpass.Password}"); CredentialUtil.RemoveCredentials("FOO"); Debug.Assert(CredentialUtil.GetCredential("FOO") == null); 

如果您有兴趣自己实现它,请浏览源代码: http : //credentialmanagement.codeplex.com/SourceControl/latest

诀窍是Credential Manager中没有C#API。 这个库很好地包装了其他.dll入口点。 🙂

这适用于Windows 2k12,我没有Win 8盒来测试

http://blogs.msdn.com/b/cdndevs/archive/2013/10/02/using-windows-8-winrt-apis-in-net-desktop-applications.aspx

简而言之

  1. 卸载项目文件
  2. 编辑它
  3. 8.0 添加到PropertyGroup部分
  4. 添加对Windows.Security的引用(您将拥有一个Windows库列表)
  5. 添加位于C:\ Program Files(x86)\ Reference Assemblies \ Microsoft \ Framework.NETCore \ v4.5中的System.Runtime.WindowsRuntime.dll

然后你可以使用它(从这里 ):

 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; } 

Randy的答案使用System.String来存储密码,这是不安全的。 您将需要使用System.Security.SecureString来实现此目的。

如果您只是阅读使用.NET Framework 2.0的Credential Management,那将会更好。

使用CredentialManagement(查看答案https://stackoverflow.com/a/17747020/206730 )。

使用Powershell也许有用:

CredMan.ps1
https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Credentials-d44c3cde

我无法列出存储的所有凭据。

 using CredentialManagement; using System.Diagnostics; namespace UnitTestProject1 { [TestClass] public class CredentialTests { [TestMethod] public void Set_Credentials_for_older_domain_whe_migration_to_new_domain() { var accesos = new List { "intranet", "intranet.xxxxx.net", "intranet.zzzzzzzz.com", "intranetescritorio.zzzzzzzz.net", "more...", }; accesos.ForEach(acceso => SaveCredential(acceso)); } private static Credential SaveCredential(string CredentialName) { var UserName = @"OLDERDOMAIN\user"; var Password = "pass"; var cm = new Credential { Target = CredentialName, Type = CredentialType.DomainPassword }; if (cm.Exists()) { cm.Load(); Console.WriteLine("Credential " + cm.Target + ". Data: " + cm.Username + " " + cm.Password); //if (cm.Type == CredentialType.Generic) cm.Delete(); return cm; } cm = new Credential { Target = CredentialName, Type = CredentialType.DomainPassword, PersistanceType = PersistanceType.Enterprise, Username = UserName, Password = Password }; cm.Save(); return cm; } }