我正在开展一个学校项目,我应该修改Windows Logon UI中提供的凭据的方式。 经过一些搜索,我找到了着名的Vista RTM(Longhorn)样品和技术文档。我发现所有样本都是用C ++开发的。
由于我没有任何C / C ++经验,我认为自己是一个体面的C#程序员,我想知道是否有可能做这个C#。
我还需要与REST API交换数据以验证登录,因此C#会更友好。
我发现了这个https://stackoverflow.com/a/23496878/3626447,但@mageos提供的信息太过" raw"。
有人知道一些有用的资源吗?
答案 0 :(得分:4)
您提供的链接完全正确。您需要在NET中实现一个COM对象,该对象实现以下两个COM接口(至少):ICredentialProvider,ICredentialProviderCredential
首先,您必须在.NET中公开它们,以便您可以引用它们。在我的经验中,更简单的方法是在Windows SDK中通过IDL。您需要的idl文件为\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\um\credentialprovider.idl
。
Catch#1:您需要将所有定义包含在library CredentialProviders { ... }
语句中,否则只有某些类型的才能导出<) / p>
打开VS本机工具并使用midl
进行编译:
midl "C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\um\credentialprovider.idl"
这将创建一个类型库(tlb文件),然后.NET可以将其用于将类型转换为C#类型。您现在可以使用tlbimp
实用程序创建一个可以在.NET中使用的interop dll:
tlbimp.exe credentialprovider.tlb /out:CredentialProvider.Interop.dll
Catch#2:不幸的是,使用tlbimp
编译剥离了方法调用(HRESULT
)的返回类型,并希望您使用.NET异常子系统。在这种情况下,这不起作用,因为winlogon(或credUI主机应用程序)重新抛出异常并终止进程。解决方案是使用名为tlbimp2
的实用程序。在撰写本文时,它在codeplex上托管了SVN - 只有代码可用。我必须下载代码并在VS2017中重新编译该工具(我已在附加的repo中上传了工件)。所以我们需要运行它来编译winlogon:
tlbImp2.exe credentialprovider.tlb /out:CredentialProvider.Interop.dll /unsafe /verbose /preservesig
现在我们可以启动一个可以实现COM对象的库。在.NET框架中启动一个DLL项目。编辑项目并确保选中“Register for COM interop”标志。参考编译的Interop库。
如前所述,我们需要实现两个接口:ICredentialProvider,ICredentialProviderCredential。代码应如下所示:
[ComVisible(true)]
[Guid("<random-guid>")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITestWindowsCredentialProvider: ICredentialProvider
{
}
您可以对ICredentialProviderCredential界面执行完全相同的操作。
关于实施:
[ComVisible(true)]
[Guid("<another-unique-id>")] // <-- This is what we are going to use for registration
[ClassInterface(ClassInterfaceType.None)]
public class TestWindowsCredentialProvider : ITestWindowsCredentialProvider
{
private const int E_NOTIMPL = unchecked((int) 0x80004001);
...
public int SetSerialization(ref _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcs)
{
return E_NOTIMPL;
}
...
}
从所有方法E_NOTIMPL
返回,并提供所有out
参数中的值。现在我们有一个基础对象,我们可以开始。您可以延迟ICredentialProviderCredential的实现,直到实现方法ICredentialProvider :: GetCredentialAt。
您可以通过在使用组件的实现guid命名的注册表设置HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers
下添加密钥来注册此凭据提供程序(请记住此处的括号)。
当您这样做时,登录服务和credUI调用将加载和查询您的组件。但请注意:任何异常都会导致winlogon崩溃,导致您无法登录。使用VM作为最佳实践。
现在,在完成所有这些步骤之后,我们仍然需要实施凭据提供程序。最好在名为Credential Provider driven Windows Logon Experience的文档中对此进行描述。您最终需要使用在后台执行的任何可能的操作来编排UI,并将其映射到用户。
在正确序列化方法实现ICredentialProviderCredential :: GetSerialization上的用户信息时,您将能够登录用户。
例我举了一个例子,您可以在这里找到它:https://github.com/phaetto/windows-credentials-provider