使用 C# 从 Windows Credentials Store 检索凭据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17741424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:22:51  来源:igfitidea点击:

Retrieve credentials from Windows Credentials Store using C#

c#credentials

提问by Kirschi

I simply want to query the Credentials Store (or Vaultas it is called in Windows 8) and get the login data. MSDN is really unhelpful in this case, and I also do not want any C++ P/Invokeapproaches.

我只想查询凭证存储(或Windows 8 中称为Vault 的存储)并获取登录数据。MSDN 在这种情况下真的没有帮助,而且我也不想要任何 C++ P/Invoke方法。

I know that similar questions have been asked here a few times, but none of those solutions work in my case. I do not use Metro App programming, so things like PasswordVaultare (as it looks) not available. I just create a simple C# WPF desktop application.

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

Ideally, it should work in several Windows versions, but Windows 8 is preferred.

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

More specifically, I want to query the stored data from the CRM plugin for Outlook to automatically have my application log in to the CRM Server without having the user to ask for his/her credentials. That means, if this is even possible...

更具体地说,我想从 Outlook 的 CRM 插件中查询存储的数据,以自动让我的应用程序登录到 CRM 服务器,而无需用户询问他/她的凭据。这意味着,如果这甚至可能......

So how do I access the Windows Credentials Store?

那么如何访问 Windows Credentials Store?

采纳答案by Randy James

There is a NuGet library that I've been using, called CredentialManagement.

我一直在使用一个 NuGet 库,称为CredentialManagement

The usage is pretty simple. I wrapped it a little, but I probably didn't need to:

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

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

Sample usage:

示例用法:

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

If you're interested in implementing it yourself, browse the source: http://credentialmanagement.codeplex.com/SourceControl/latest

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

The trick is that there is no C# API into the Credential Manager. This library wraps the other .dll entry points nicely. :-)

诀窍是凭证管理器中没有 C# API。这个库很好地包装了其他 .dll 入口点。:-)

回答by user1735022

The answer from Randy uses System.Stringto store the password, which is unsafe. You will want to use System.Security.SecureStringfor that purpose.

Randy 的答案System.String用于存储密码,这是不安全的。您将要System.Security.SecureString用于该目的。

You would be better off if you just read Credential Management with the .NET Framework 2.0.

如果您只是阅读Credential Management with the .NET Framework 2.0 ,那会更好。

回答by L1011

This works from a Windows Server 2012. I don't have a Windows 8 box to test from.

这适用于Windows Server 2012。我没有要测试的 Windows 8 盒子。

Using Windows 8 WinRT APIs in .NET Desktop Applications

在 .NET 桌面应用程序中使用 Windows 8 WinRT API

In short

简而言之

  1. Unload project file
  2. Edit it
  3. Add <TargetPlatformVersion>8.0</TargetPlatformVersion> to the PropertyGrouppart
  4. Add reference to Windows.Security (you'll have a list of Windows Libraries)
  5. Add System.Runtime.WindowsRuntime.dlllocated in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5
  1. 卸载项目文件
  2. 编辑它
  3. 将 <TargetPlatformVersion>8.0</TargetPlatformVersion> 添加到PropertyGroup部分
  4. 添加对 Windows.Security 的引用(您将获得 Windows 库列表)
  5. 添加System.Runtime.WindowsRuntime.dll位于C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5

You can then use this (from here):

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

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

回答by Kiquenet

Using CredentialManagement (view answer Retrieve credentials from Windows Credentials Store using C#).

使用 CredentialManagement(查看答案Retrieve credentials from Windows Credentials Store using C#)。

It may be useful using PowerShell too:

使用 PowerShell 也可能很有用:

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

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

I cannot list all credentials stored.

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

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<string> {
            "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;
        }
    }