0

我正在编写的软件即将采取行动,需要当前登录的用户实际上是采取行动的人。所以我想让 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 而不解压它返回的缓冲区来验证登录?

4

0 回答 0