CefAuthCallback::Continue() 如何在 GetAuthCredentials 方法之外调用它

CefAuthCallback::Continue() how to call it outside the GetAuthCredentials method

本文关键字:方法 调用 GetAuthCredentials Continue CefAuthCallback      更新时间:2023-10-16

我正在使用CEF3在C++编写应用程序。我需要对https页面进行身份验证,并且使用CefRequestHandler::GetAuthCredentials

bool GetAuthCredentials( CefRefPtr< CefBrowser > browser, CefRefPtr< CefFrame > frame, bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr< CefAuthCallback > callback );

根据文档:

返回 true 以继续请求,并在此方法中或在稍后身份验证信息可用时调用 CefAuthCallback::Continue()。返回 false 可立即取消请求。

我尝试保存 CefAuthCallback 指针以便以后使用它,但一旦我尝试调用 Continue 它,我就会崩溃。

任何示例或想法如何从 GetAuthCredentials 方法外部调用继续?

可能是线程问题或 CefAuthCallback 缓存不正确。

我在(Windows)实现中所做的是这样的。
0. 在 IO 线程上调用 GetAuthCredentials
1. 将所有 GetAuthCredentials 参数缓存到一个结构

struct auth_credentials_param_t {
    CefRefPtr<CefBrowser> browser;
    bool isProxy;
    CefString host;
    int port;
    CefString realm;
    CefString scheme;
    CefRefPtr<CefAuthCallback> auth_callback;
    bool result;
    auth_credentials_param_t(CefRefPtr<CefBrowser> browser, 
        bool isProxy, 
        const CefString& host, int port,
        const CefString& realm, const CefString& scheme, 
        CefRefPtr<CefAuthCallback> auth_callback) 
        : browser(browser)
        , isProxy(isProxy)
        , host(host)
        , port(port)
        , realm(realm)
        , scheme(scheme)
        , auth_callback(auth_callback)
        , result(false) {
    }
};
  1. GetAuthCredentials的实现是这样的:

    std::unique_ptr<auth_credentials_param_t> acp(
        new auth_credentials_param_t(
        browser, 
        isProxy, host, port, realm, scheme, 
        callback));
    m_pMainWindow->HandleAuthCredentials(
        acp.release());
    return true;
    

顾名思义,m_pMainWindow是主窗口实现。
(我们仍在 IO 线程上)。

  1. MainWindow 类有两个成员(第一个是来自客户端处理程序的实际调用,第二个只是 IO 到 UI 线程任务回调 - 见下文):

    void HandleAuthCredentials(
        auth_credentials_param_t* acp);
    static void CBHandleAuthCredentials(
        MainWindow* pMW, 
        auth_credentials_param_t* acp);
    

像这样实现(见下文)。
MainWindow::HandleAuthCredentials需要在UI线程上运行,因此第一次从IO线程调用,当线程!= UI时,使用CefPostTask重新发布对UI线程的调用。CBHandleAuthCredentials只是调用HandleAuthCredentials,这次是在UI线程中。

    void MainWindow::CBHandleAuthCredentials(
        MainWindow* pMW, 
        auth_credentials_param_t* acp)
    {
        pMW->HandleAuthCredentials(acp);
    }
    void MainWindow::HandleAuthCredentials(
        auth_credentials_param_t* acp_ptr
    ) {
        if(this == nullptr) {
            return; }
        std::unique_ptr<auth_credentials_param_t> acp(acp_ptr);
        if(!acp.get()) {
            return; }
        if(!CefCurrentlyOn(TID_UI)) {
            CefPostTask(
                TID_UI, 
                base::Bind(
                    &MainWindow::CBHandleAuthCredentials, 
                    this, 
                    acp.release()
                )
            );        
            return; }
        CEF_REQUIRE_UI_THREAD();
        // here follows the logic of authentication
        // for example, have an authentication cache
        // and if user, pass and host matches, continue, else present an 
        // authentication dialog to the user
        //
        // ... code omitted for brevity
        //
        // browser_auth_info_t is a wrapper structure containing 
        // host, port, realm, scheme, user, password, 
        // remember flag, and browser identifier
        // m_AuthCache is a collection of browser_auth_info_t
        // 
        std::vector<browser_auth_info_t> entries;
        if(m_AuthCache.findAuthCacheEntries(sTarget, entries)) {
            // if multiple (even this should not happen), pick first
            std::wstring user = entries[0].user();
            std::wstring pass = entries[0].pass();
            // mark this entry as active
            browser_auth_info_t entry = entries[0];
            m_AuthCache.markEntryAsActive(entry);
            //  inform authentication to continue
            CefString username = user;
            CefString password = pass;
            acp->auth_callback->Continue(user, pass);
            acp->result = true;       
        }
        else {
            //  we cannot supply credentials from cache
            //  display logon dialog
            browser_auth_info_t bi(
                acp->browser->GetIdentifier(), 
                acp->host.ToWString(), 
                acp->port, 
                acp->realm.ToWString(), 
                acp->scheme.ToWString());
            std::wstring sUser;
            std::wstring sPass;
            bool remember = false;
            INT_PTR result = CDlgAuth::Display(g_hUiTxtInstance, 
                get_hwnd(), &bi, sUser, sPass, remember);
            if(result != IDOK) {
                //  user canceled the authentication dialog
                acp->result = false;
                acp->auth_callback->Cancel();
                break;
            }
            else {
                //  user provided auth info
                //  update the cache with provided credentials
                bi.update(sUser, sPass, remember);
                m_AuthCache.updateEntryPassword(&bi);
                //  inform authentication to continue
                CefString username = sUser;
                CefString password = sPass;
                acp->auth_callback->Continue(username, password);
                acp->result = true;
                break;
            }
        }