我正在编写的一种软件即将采取措施,要求当前登录的用户实际上是采取该措施的用户。因此,我想让Windows在允许操作继续之前先询问当前用户的密码或生物识别信息或其他信息。
我在另一篇文章(以下代码)中为UserConsentVerifier使用了互操作性。
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Security.Credentials.UI;
namespace UWPInterop
{
//MIDL_INTERFACE("39E050C3-4E74-441A-8DC0-B81104DF949C")
//IUserConsentVerifierInterop : public IInspectable
//{
//public:
// virtual HRESULT STDMETHODCALLTYPE RequestVerificationForWindowAsync(
// /* [in] */ HWND appWindow,
// /* [in] */ HSTRING message,
// /* [in] */ REFIID riid,
// /* [iid_is][retval][out] */ void** asyncOperation) = 0;
//};
[System.Runtime.InteropServices.Guid("39E050C3-4E74-441A-8DC0-B81104DF949C")]
[System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIInspectable)]
public interface IUserConsentVerifierInterop
{
IAsyncOperation<UserConsentVerificationResult> RequestVerificationForWindowAsync(IntPtr appWindow, [MarshalAs(UnmanagedType.HString)] string Message, [In] ref Guid riid);
}
//Helper to initialize UserConsentVerifier
public static class UserConsentVerifierInterop
{
public static IAsyncOperation<UserConsentVerificationResult> RequestVerificationForWindowAsync(IntPtr hWnd, string Message)
{
IUserConsentVerifierInterop userConsentVerifierInterop = (IUserConsentVerifierInterop)WindowsRuntimeMarshal.GetActivationFactory(typeof(UserConsentVerifier));
Guid guid = typeof(IAsyncOperation<UserConsentVerificationResult>).GUID;
return userConsentVerifierInterop.RequestVerificationForWindowAsync(hWnd, Message, ref guid);
}
}
}
如果设置了Windows Hello,此方法就可以正常工作。如果没有错误或类似错误,它将返回DeviceNotPresent。尝试查找提供Windows密码的替代方法。该代码有效,但是我对应用程序内存中使用的密码并不满意。 (C ++ / CLR)
bool ValidateUser(String ^caption, String ^message)
{
bool result = false;
String^ userName = WindowsIdentity::GetCurrent()->Name;
std::wstring strUsername = marshal_as<std::wstring>(userName);
std::wstring strCaption = marshal_as<std::wstring>(caption);
std::wstring strMessage = marshal_as<std::wstring>(message);
CREDUI_INFOW info;
ZeroMemory(&info, sizeof(info));
info.cbSize = sizeof(info);
info.pszMessageText = strMessage.c_str();
info.pszCaptionText = strCaption.c_str();
ULONG authPackage = 0;
LPVOID pOut;
ULONG bufSize;
DWORD inBuffer = 0;
std::vector<uint8_t> credBuffer;
if (!CredPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, (LPWSTR)strUsername.c_str(), L"", NULL, &inBuffer)
&& ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
{
credBuffer.resize(inBuffer);
if (!CredPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, (LPWSTR)strUsername.c_str(), L"", credBuffer.data(), &inBuffer))
{
return false;
}
}
DWORD dwResult = CredUIPromptForWindowsCredentialsW(&info, 0, &authPackage, credBuffer.data(), inBuffer, &pOut, &bufSize, NULL, CREDUIWIN_GENERIC | CREDUIWIN_IN_CRED_ONLY);
if (dwResult == ERROR_SUCCESS)
{
DWORD dwUserLength = 0;
DWORD dwDomainLength = 0;
DWORD dwPasswordLength = 0;
try
{
if (!::CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, pOut, bufSize, nullptr, &dwUserLength, nullptr, &dwDomainLength, nullptr, &dwPasswordLength)
&& ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
{
std::vector<wchar_t> bufferUser(dwUserLength);
std::vector<wchar_t> bufferDomain(dwDomainLength);
std::vector<wchar_t> bufferPassword(dwPasswordLength);
if (::CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS, pOut, bufSize, bufferUser.data(), &dwUserLength, bufferDomain.data(), &dwDomainLength, bufferPassword.data(), &dwPasswordLength))
{
HANDLE hToken;
std::wstring strUsername = bufferUser.data();
std::wstring strDomain;
if (bufferDomain.size() == 0)
{
std::wstring::size_type pos = strUsername.find(L'\\');
if (pos != std::wstring::npos)
{
strDomain = strUsername.substr(0, pos);
strUsername = strUsername.substr(pos + 1, strUsername.size() - pos - 1);
}
}
else
{
strDomain = bufferDomain.data();
}
try
{
if (::LogonUserW(strUsername.c_str(), strDomain.c_str(), bufferPassword.data(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
result = true;
}
catch (...) // Catch so memory can be cleared
{
}
ClearBuffer(bufferUser.data(), dwUserLength);
ClearBuffer(bufferDomain.data(), dwDomainLength);
ClearBuffer(bufferPassword.data(), dwPasswordLength);
}
}
}
catch(...) // Catch so memory can be cleared
{
}
ClearBuffer(pOut, bufSize);
CoTaskMemFree(pOut);
}
return result;
}
有没有一种方法可以使用CredUIPromptForWindowsCredentialsW而不解压缩它返回来验证登录名的缓冲区?