原帖地址:https://www.cnblogs.com/guolixiucai/p/6994559.html

涉及网页登录相关的技术,Cookies肯定是忽略不了的。由于项目的需要,要做一个双核的产品。双核间切换会涉及到登录状态的问题,共享Cookies是一个很好的方案。既然涉及到共享cookies,那么读取完整的cookies和设置cookies就是问题的关键。由于应用本身只需要加载自家的平台,不用考虑共享所有网站cookie的问题,所以需要获取的和设置的cookies相对比较简单。
IE浏览器内核Cookies的获取和设置相对难一点,但是好在网络上资料比较多。Chromium内核基于CEF3框架,获取和设置cookies有现成的接口。在这里主要总结的是IE浏览器内核Cookies的获取和基于CEF3框架的Cookies设置以及获取。

IE浏览器内核的Cookies获取的三种方式:
1、通过读取存在硬盘上的cookies文件,来获取指定网站的cookies;
2、通过用MSHTMLI的Dispatch接口IWebBrowser2和IHTMLDocument2来获取cookies;
3、通过API函数InternetGetCookieEx和InternetGetCookie来获取cookies;
4、通过Hook WINNET 相关的函数获取Cookies,HOOK住发送和接收包API(send、recv、WSASend、WSARecv等)。然后分析HTTP header。此处不讲。
第一种方式,实现起来比较笨重,一般作为后边两种方式的补充。实现代码如下:

std::wstring GetCookiesUnderIE7( wstring strDomain )
{
wstring strCookiePath;
TCHAR dataPath[MAX_PATH];
::SHGetSpecialFolderPath(NULL, dataPath, CSIDL_COOKIES, FALSE);
strCookiePath = dataPath; TCHAR szUserName[];
DWORD cbUserName;
cbUserName = ;
GetUserName(szUserName, &cbUserName);
WIN32_FIND_DATA FindData;
HANDLE hfile;
DWORD errorcode = ;
hfile = FindFirstFile((strCookiePath + L"\\*.txt").c_str() ,&FindData);
wstring wsUserName = szUserName;
wstring wsCookieName = wsUserName + L"@xx"; //xx为网站域名,如百度的baidu
wstring wsFileName;
wstring wsCookies = L"";
hile(hfile!= INVALID_HANDLE_VALUE && errorcode != ERROR_NO_MORE_FILES)
{
wsFileName = FindData.cFileName;
//判断是否存在【user】@xx为名称的cookie脚本,提高过滤效率
if (wsFileName.find(wsCookieName.c_str()) != wstring::npos)
{
wsFileName = strCookiePath + L"\\"+ FindData.cFileName;
//http://www.cnblogs.com/guolixiucai/;
std::ifstream ifsCookie(wsFileName.c_str(), std::ios::in | std::ios::binary);
if (ifsCookie)
{
std::string contents;
ifsCookie.seekg(, std::ios::end);
contents.resize(ifsCookie.tellg());
ifsCookie.seekg(, std::ios::beg);
ifsCookie.read(&contents[], contents.size());
if(contents.find("ispass_37wan_com") != string::npos)
{
wsCookies = s2ws(contents);
ifsCookie.close();
break;
}
ifsCookie.close();
}
} BOOL flag = TRUE;
BOOL isNextFile = FindNextFile(hfile,&FindData);//判断该目录下是否还有文件
if(flag == TRUE && isNextFile == TRUE)//如果还有文件,则调用SetLastError,设为NO_ERROR,这样才能继续遍历后面的文件
SetLastError(NO_ERROR);
else
errorcode=GetLastError();
}
return wsCookies;
}

第二种方式获取的Cookies并不完全,只能获取到部分Cookies
IHTMLDocument2::get_cookie()
IHTMLDocument2::put_cookie()
用MSHTML对Document对象的Cookie属性进行操作。也可以实现类似InternetGetCookie和InternetSetCookie的效果。实际上它等同于用javascript来读写文档中的Cookie。它同样可以获取、添加、覆盖、修改、删除持久Cookie和会话级Cookie,但不可读写HTTPOnly的Cookie。这种方式同样也要十分注意设置的Cookie的每个属性都要和目标Cookie一一对应才能正确操作Cookie。特别是Path和Domain属性,否则会导致添加了一个同名Cookie而不能覆盖或清除目标Cookie的结果。
代码如下:

std::wstring BrowserView::GetCookies()
{
CComPtr<IWebBrowser2> webBrowser;
HRESULT hr = QueryControl(IID_IWebBrowser2,
reinterpret_cast<void**>(&webBrowser));
if (FAILED(hr) || (!webBrowser))
return L""; CComPtr<IDispatch> disp;
hr = webBrowser->get_Document(&disp);
if (FAILED(hr) || (!disp))
return L""; CComPtr<IHTMLDocument2> document;
hr = disp->QueryInterface(IID_IHTMLDocument2,
reinterpret_cast<void**>(&document));
if (FAILED(hr) || (!document))
return L""; BSTR bstrCookie;
hr = document->get_cookie(&bstrCookie);
BSTR bstrDomain;
document->get_domain(&bstrDomain);
if (FAILED(hr))
{
return L"";
}
wstring strCookie(bstrCookie);
char* lpszText2 = _com_util::ConvertBSTRToString(bstrCookie);
SysFreeString(bstrCookie);
return strCookie;
}

第三种方式:
InternetGetCookie
InternetSetCookie
InternetGetCookieEx
InternetSetCookieEx
这些API属于Wininet,可以获取、添加、覆盖、修改、删除持久Cookie和会话级Cookie(会话级Cookie需要在同进程中操作)。加Ex后缀的API可以对HTTPOnly的Cookie进行操作。但这组API对IE7及以下的IE浏览器内核无效,取不到Cookies,这时候就需要使用第一种方法补充。当然也可以使用其他比较复杂的方法,例如Hook WINNET 相关的函数。

std::wstring GetCookies( wstring strDomain )
{
LPDWORD lpdwSize = new DWORD;
wchar_t strCookie[] = {};
int size = ;
//InternetGetCookie 取不到httponly的cookie,留在这里仅供后来者参考
// InternetGetCookie(strDomain.c_str(), NULL, NULL, lpdwSize);
// InternetGetCookie(strDomain.c_str(), NULL, strCookie, lpdwSize/*, INTERNET_COOKIE_HTTPONLY, NULL*/); //InternetGetCookieEx 在IE7和IE6里也是取不全cookie。
InternetGetCookieEx(strDomain.c_str(), NULL, strCookie, lpdwSize, 0x2000, NULL);
wstring wsCookies = strCookie;
return wsCookies;
}

CEF3中Cookies的管理。
如果不想听我啰嗦,移步http://magpcss.org/ceforum/apidocs3/projects/(default)/CefCookieManager.html
下边的内容基本上是翻译这个文档,在加上两个实例。
CEF3中,CefCookieManager这个类就是用来管理cookies的。在头文件cef_cookies中,在cef_cookies_capi.h里,有详细的注释,和上边链接里的文档说明一样。
Cookies的管理无外乎Cookies的设置、获取、删除、查找,外加一个存储位置的设置。

class CefCookieManager
extends CefBase 
Class used for managing cookies. The methods of this class may be called on any thread unless otherwise indicated. 
该类用来管理cookies。除非另有说明,该类的方法可以在任何线程中调用

Method Summary
 static CefRefPtr< CefCookieManager > CreateManager( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback ) 
          Creates a new cookie manager.
 virtual bool DeleteCookies( const CefString& url, const CefString& cookie_name, CefRefPtr< CefDeleteCookiesCallback > callback )= 0 
          Delete all cookies that match the specified parameters.
 virtual bool FlushStore( CefRefPtr< CefCompletionCallback > callback )= 0 
          Flush the backing store (if any) to disk.
 static CefRefPtr< CefCookieManager > GetGlobalManager( CefRefPtr< CefCompletionCallback > callback ) 
          Returns the global cookie manager.
 virtual bool SetCookie( const CefString& url, const CefCookie& cookie, CefRefPtr< CefSetCookieCallback > callback )= 0 
          Sets a cookie given a valid URL and explicit user-provided cookie attributes.
 virtual bool SetStoragePath( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback )= 0 
          Sets the directory path that will be used for storing cookie data.
 virtual void SetSupportedSchemes( const std::vector< CefString >& schemes, CefRefPtr< CefCompletionCallback > callback )= 0 
          Set the schemes supported by this manager.
 virtual bool VisitAllCookies( CefRefPtr< CefCookieVisitor > visitor )= 0 
          Visit all cookies on the IO thread.
 virtual bool VisitUrlCookies( const CefString& url, bool includeHttpOnly, CefRefPtr< CefCookieVisitor > visitor )= 0 
          Visit a subset of cookies on the IO thread.

Method Detail
CreateManager
public static CefRefPtr< CefCookieManager > CreateManager( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback );
创建一个新的cookie管理器,当|path|没有被设置时,数据存储在内存中。否则,数据保存在指定的|path|(如果在cef初始化时,指定了缓存路径,那么cookies会保存在此路径)。持久化会话cookies(没有有效期或有效区域),需要设置|persist_session_cookies| 为true。会话cookies一般是暂时性的并且大多数浏览器并不支持。如果|callback| 为 non-NULL ,那么在管理器存储空间初始化后,会在IO线程中异步执行。

DeleteCookies
public virtual bool DeleteCookies( const CefString& url, const CefString& cookie_name, CefRefPtr< CefDeleteCookiesCallback > callback )= 0;
删除与指定参数的相匹配的所有cookies。如果 |url| 和 |cookie_name| 都被指定,那么 host和domian与这两个参数匹配的都被删除。如果 |url|为空,那么所有的hosts 和domains的cookies都没清空。如果|callback| 为 non-NULL ,那么在cookies被删除后,该回调函数会在IO线程中异步执行。如果不存在指定的url或者cookies不能被访问,那么返回falsh。cookies可以通过交替使用Visit*Cookies()方法被删除。

//向指定的域名删除cookies

void ClientAppBrowser::DeleteCookies( std::wstring domain, std::wstring cookiename )
{
CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(NULL);
DCHECK(manager.get());
CefRefPtr<CefDeleteCookiesCallback> callback = NULL;
std::wstring httpDomain = domain;
CefString cookie_name;
cookie_name.FromWString(cookiename .c_str());
base::IgnoreResult(&CefCookieManager::DeleteCookies);
CefPostTask(TID_IO, NewCefRunnableMethod(manager.get(), &CefCookieManager::DeleteCookies,
CefString(httpDomain.c_str()), cookie_name, callback));
}

FlushStore
public virtual bool FlushStore( CefRefPtr< CefCompletionCallback > callback )= 0;
将备份存储(如果存在)缓存到硬盘,如果|callback| 为 non-NULL ,在缓存完后,该回调函数会在IO线程中异步执行。cookies不能被访问则返回falsh。

GetGlobalManager
public static CefRefPtr< CefCookieManager > GetGlobalManager( CefRefPtr< CefCompletionCallback > callback );
返回全局cookie管理器,默认存储路径是 CefSettings.cache_path或者其他指定路径,否则存储在内存。如果|callback| 为 non-NULL ,在管理器存储空间初始化后,该回调函数会在IO线程中异步执行。该方法与调用CefRequestContext::GetGlobalContext()->GetDefaultCookieManager()相当

SetCookie
public virtual bool SetCookie( const CefString& url, const CefCookie& cookie, CefRefPtr< CefSetCookieCallback > callback )= 0;
设置一个指定了url和由用户设置了属性的cookie。该方法需要每个属性有符合良好的格式。检查非法字符(例如“;”存在cookie属性值中),存在非法字符会导致cookies设置失败。如果|callback| 为 non-NULL ,那么在cookies被设置后,该回调函数会在IO线程中异步执行。指定的url不存在或者cookies不能被访问,返回falsh。

实例

void ClientAppBrowser::SetCookies( std::wstring domain, std::wstring key, std::wstring svalue )
{
/*
向指定的域名写Cookie http://www.cnblogs.com/guolixiucai/
*/
CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(NULL);
DCHECK(manager.get());
CefRefPtr<CefSetCookieCallback> callback = NULL;
CefCookie cookie;
CefString(&cookie.name).FromWString(key.c_str());
CefString(&cookie.value).FromWString(svalue.c_str());
CefString(&cookie.domain).FromWString(domain.c_str());
CefString(&cookie.path).FromASCII("/");
cookie.has_expires = true;
//以下过期时间随意设置的。
cookie.expires.year = ;
cookie.expires.month = ;
cookie.expires.day_of_week = ;
cookie.expires.day_of_month = ;
std::wstring httpDomain = L"http://www";
httpDomain.append(domain);
base::IgnoreResult(&CefCookieManager::SetCookie);
CefPostTask(TID_IO, NewCefRunnableMethod(manager.get(), &CefCookieManager::SetCookie,
CefString(httpDomain.c_str()), cookie, callback));
}

SetStoragePath
public virtual bool SetStoragePath( const CefString& path, bool persist_session_cookies, CefRefPtr< CefCompletionCallback > callback )= 0;
设置存储cookies数据的路径。如果|path|为空,则存储在内存中。持久化会话cookies(没有有效期或有效区域),需要设置|persist_session_cookies| 为true。会话cookies一般是暂时性的并且大多数浏览器并不支持。如果|callback| 为 non-NULL ,那么在管理器存储空间初始化后,会在IO线程中异步执行。

SetSupportedSchemes
public virtual void SetSupportedSchemes( const std::vector< CefString >& schemes, CefRefPtr< CefCompletionCallback > callback )= 0;
设置管理器支持的协议。支持常见的协议("http", "https", "ws" and "wss")。如果|callback| 为 non-NULL ,在协议更改生效后,该回调函数会在IO线程中异步执行。该方法必须在所有cookies被访问前调用

VisitAllCookies
public virtual bool VisitAllCookies( CefRefPtr< CefCookieVisitor > visitor )= 0;
访问IO线程中所有的Cookies。返回的cookies按照最长路径排序,然后再按照最长创建时间排序。如果cookies被占用则返回false。

VisitUrlCookies
public virtual bool VisitUrlCookies( const CefString& url, bool includeHttpOnly, CefRefPtr< CefCookieVisitor > visitor )= 0;
访问IO线程上的一组Cookie。返回结果可按照url、host、domain和路径过滤。如果|includeHttpOnly|为ture,那么结果中还会包含HTTP-only cookies。返回的cookies按照最长路径排序,然后再按照最长创建时间排序。如果cookies被占用则返回false。

原帖地址:https://www.cnblogs.com/guolixiucai/p/6994559.html

CEF3开发者系列之Cookies管理和共享<转>的更多相关文章

  1. CEF3开发者系列之Cookies管理和共享

    涉及网页登录相关的技术,Cookies肯定是忽略不了的.由于项目的需要,要做一个双核的产品.双核间切换会涉及到登录状态的问题,共享Cookies是一个很好的方案.既然涉及到共享cookies,那么读取 ...

  2. CEF3开发者系列之进程和线程

    CEF3是一个多进程架构框架,如果有了解过chromium的进程架构的,那么就很容易了解CEF3的多进程了.打开CEF3源代码中发布的cefclient实例,如果打开的页面带有flash或者其他插件. ...

  3. CEF3开发者系列之类和接口

    CEF3基本的框架包含C/C++程 序接口,通过本地库的接口来实现,而这个库则会隔离宿主程序和 Chromium&Webkit的操作细节.它在浏览器控件和宿主程序之间提供紧密的整合,它支持用户 ...

  4. CEF3开发者系列之工程和代码结构

    CEF支持一系列的编程语言和操作系统,并且能很容易地整合到新的或已有的工程中去.它的设计思想就是易用且兼顾性能. CEF3支持一系列的编程语言和操作系统,并且能很容易地整合到新的或已有的工程中去.它的 ...

  5. CEF3开发者系列之CEF3入门

    CEF全称Chromium Embedded Framework,是一个基于Google Chromium 的开源项目.Google Chromium项目主要是为Google Chrome应用开发的, ...

  6. CEF3开发者系列之外篇——IE中JS与C++交互

    使用IE内核开发客户端产品,系统和前端页面之间的交互,通常给开发和维护带来很大的便利性.但操作系统和前端之间的交互却是比较复杂的.具体来说就是脚本语言和编译语言的交互.在IE内核中html和css虽然 ...

  7. CEF3开发者系列之JS与C++交互之二

    本文翻译自JavaScriptIntegration (https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration).本 ...

  8. CEF3开发者系列之JS与C++交互之一

    JS与Native交互是相对于比较困难的技术,在学习这门技术之前,我们先了解下浏览器内核中的JS引擎与chromium内核的V8引擎相关知识.在浏览器应用中,JS与本地代码互相调用,得益于浏览器内核对 ...

  9. CEF3开发者系列之进程间消息传递

    在使用CEF3作为框架开发过程中,实现WebSockets.XMLHttpRequest.JS与本地客户端交互等功能时,需要在渲染(Render)进程和浏览(Browser)进程中传递消息.CEF3在 ...

随机推荐

  1. 解决远程连接数据库:Host is not allowed to connect to this MySQL server

    远程连接数据时,报以下提示: Host 'web1' is not allowed to connect to this MySQL server 原因是数据库服务不允许远程登录,没有授权导致,解决方 ...

  2. 【MySQL】SQL语句基础

    一.操作数据库 1.1 创建数据库 1.2 查看数据库 1.3 修改数据库 1.4 删除数据库 1.5 选择数据库 二.操作表 2.1 创建表 2.2 查看表 2.3 修改表 2.4 删除表 三.操作 ...

  3. Find 命令记录

    当需要查找一个时间的文件时 使用find [文件目录] -mtime [时间] 例如:查看mysql.bak目录下的1天前的文件 find mysql.bak -mtime 找到此文件之后需要将它移动 ...

  4. There is no getter for property named 'PRODUCT_ID' in 'class java.lang.String'

    背景:心血来潮之际,准备搭建以下多月未曾碰触过的Mybatis框架,体验一番原生之美.殊不知能力有限,错误百出.特抒此文以纪念此坑.问题:想在sql管理中来统一处理一些简单的判断,但是添加判断之后参数 ...

  5. docker镜像批量打包

    docker镜像批量打包 批量打包镜像: # docker save $(docker images | grep -v REPOSITORY | awk 'BEGIN{OFS=":&quo ...

  6. 时间模块time和datetime的使用

    日期和时间 一 time模块 import time 时间的表示形式: 时间戳 时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现 ...

  7. ASP.NET Core 2.2 项目升级至 3.0 备忘录

    将 ASP.NET Core 2.2 迁移至 ASP.NET Core 3.0 需要注意的地方记录在这篇随笔中. TargetFramework 改为 netcoreapp3.0 <Target ...

  8. 帝国CMS熊掌号数据主动推送插件【原创】

    因为昨晚一个朋友他是帝国CMS做的网站,叫我给他做个熊掌号改造和熊掌号推送,所以花了一个小时时间做了这个插件,有需要的朋友可以拿去. 第一步:在后台执行以下数据库语句: CREATE TABLE `b ...

  9. oracle 查询月份

    ①:select substr(to_char(sysdate,'yyyy-mm-dd'),6,2) from dual; ②:select to_char(sysdate,'MM') from du ...

  10. jmeter 压测工具安装及使用

    linux下jmeter安装: 1. 下载JMeter官方网站下载最新版本: http://jmeter.apache.org/download_jmeter.cgi ,目前最新版是Apache JM ...