我正在使用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) {
}
};
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 线程上)。
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;
}
}