我一直在研究一个连接到服务器的服务,该服务使用数字签名作为验证用户访问页面。为了能够连接到网页并使用它,我使用了 "WebBrowser "类 (https:/docs.microsoft.coms-esdotnetapisystem.windows.forms.webbrowser?view=netcore-3.1。)
事实上,当到达网页时,这个窗口会弹出,让我在电脑中选择一个可能的证书来识别自己。
为了解决这个问题,我在网上搜索了一下,发现了不同的潜在解决方案,但没有一个能充分地解决这个问题。
为了解决这个问题,我在类中加入了下面的代码,这样我就可以从WebBrowser中捕获函数调用。
[Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface UCOMIServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(
[In] ref Guid guidService,
[In] ref Guid riid,
[Out] out IntPtr ppvObject);
}
[ComImport()]
[ComVisible(true)]
[Guid("79eac9d5-bafa-11ce-8c82-00aa004ba90b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IWindowForBindingUI
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetWindow(
[In] ref Guid rguidReason,
[In, Out] ref IntPtr phwnd);
}
[ComImport()]
[ComVisible(true)]
[Guid("79eac9d7-bafa-11ce-8c82-00aa004ba90b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IHttpSecurity
{
//derived from IWindowForBindingUI
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int GetWindow(
[In] ref Guid rguidReason,
[In, Out] ref IntPtr phwnd);
[PreserveSig]
int OnSecurityProblem(
[In, MarshalAs(UnmanagedType.U4)] uint dwProblem);
}
还有一个函数可以在出现问题的时候知道并尝试解决它。
public int OnSecurityProblem(uint dwProblem)
{
int dwCertSelection2 = 2;
IntPtr dwCertSelection = new IntPtr(dwCertSelection2);
//ignore errors
//undocumented return code, does not work on IE6
if (dwProblem == 12044)
{
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2 x509 = fcollection[2];
IntPtr unmanagedPointer = Marshal.AllocHGlobal(x509.RawData.Length);
Marshal.Copy(x509.RawData, 0, unmanagedPointer, x509.RawData.Length);
bool VF_Resultado = WinHttpSetOption(this.myWebBrowser.Handle, 47, unmanagedPointer, x509.RawData.Length);
Marshal.FreeHGlobal(unmanagedPointer);
store.Close();
return RPC_E_RETRY;
}
return S_OK;
}
为了更清楚地说明问题:
if (dwProblem == 12044) --> /12044, ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED. 这说明我们需要通过一个认证
bool VF_Resultado = WinHttpSetOption(this.myWebBrowser.Handle, 47, unmanagedPointer, x509.RawData.Length); --> /INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT 47,理论上有了这个函数,我们可以不用选择就可以指明我们要使用的认证。
这段代码基于不同的来源(我尝试了两种解决方案,但没有成功)。
https:/docs.microsoft.comen-uswindowswin32winhttpssl-in-whttp。
问题是这段代码并没有起到预期的作用,我有各种疑问,能不能保证它的工作。
谢谢您
经过多次测试和审查,我得出的结论是,使用webBrowser控件不可能做到这一点,这是由于要通过认证必须使用这个函数。
WinHttpSetOption(this.myWebBrowser.Handle, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, dwCertSelection, size)
这里的主要问题是WinHttpSetOption需要调用函数 "HttpOpenRequest "后返回的处理程序会话。
https:/docs.microsoft.comen-uswindowswin32winhttphinternet-handles-in-winhttp#handle-hierarchy。
一个不能从C# WebBrowser对象中获得的数据。