百度 AIP 开放平台使用 OAuth2.0 授权调用开放 API,调用 API 时必须在 URL 中带上 access_token 参数。
请求 URL 数据格式 授权服务地址:https://aip.baidubce.com/oauth/2.0/token 
请求参数如下:
grant_type: 必须参数,固定为 client_credentials; 
client_id: 必须参数,应用的 API Key; 
client_secret: 必须参数,应用的 Secret Key; 
 
获取结果 服务器返回的JSON文本参数如下:
access_token: 要获取的 Access Token; 
expires_in: Access Token 的有效期(秒为单位,一般为 1 个月); 
其他参数忽略,暂时不用; 
 
以下代码为示例:
{   "refresh_token" :  "25.b55fe1d287227ca97aab219bb249b8ab.315360000.1798284651.282335-8574074" ,    "expires_in" :  2592000 ,    "scope" :  "public wise_adapt" ,    "session_key" :  "9mzdDZXu3dENdFZQurfg0Vz8slgSgvvOAUebNFzyzcpQ5EnbxbF+hfG9DQkpUVQdh4p6HbQcAiz5RmuBAja1JJGgIdJI" ,    "access_token" :  "24.6c5e1ff107f0e8bcef8c46d3424a0e78.2592000.1485516651.282335-8574074" ,    "session_secret" :  "dfac94a3489fe9fca7c3221cbf7525ff"  } 
若请求错误,服务器将返回的 JSON 文本包含以下参数:
error: 错误码;关于错误码的详细信息请参考下方鉴权认证错误码。 
error_description: 错误描述信息,帮助理解和解决发生的错误。 
 
以下为请求错误返回结果:
{     "error" :  "invalid_client" ,      "error_description" :  "unknown client id"  } 
error 
error_description 
解释 
 
 
invalid_client 
unknown client id 
API Key不正确 
 
invalid_client 
Client authentication failed 
Secret Key不正确 
 
 
 
C++ 代码 #include  <curl/curl.h>  #include  <string>  #include  <map>  #include  <iostream>  #include  <fstream>  #include  <json/json.h>  size_t  writeCallback (void  *ptr, size_t  size, size_t  nmemb, void  *userdata) 	std::string *str = dynamic_cast <std::string *>((std::string *)userdata); 	str->append ((char  *)ptr, size * nmemb); 	return  size * nmemb; } std::string getTokenKey ()   {	std::string url = "https://aip.baidubce.com/oauth/2.0/token" ; 	std::string apikey = "这里更改为对应应用的 API Key" ; 	std::string secritkey = "这里更改为对应应用的 Secrit Key" ; 	std::map<std::string, std::string> params; 	std::string response; 	params["grant_type" ] = "client_credentials" ; 	params["client_id" ] = apikey; 	params["client_secret" ] = secritkey; 	 	for  (auto  it = params.begin (); it != params.end (); ++it) { 		url += (it == params.begin () ? "?"  : "&" ) + it->first + "="  + it->second; 	} 	CURL *curl = curl_easy_init (); 	struct  curl_slist  * slist = NULL ; 	curl_easy_setopt (curl, CURLOPT_URL, url.c_str ()); 	curl_easy_setopt (curl, CURLOPT_HTTPHEADER, slist); 	curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writeCallback);   	curl_easy_setopt (curl, CURLOPT_WRITEDATA, &response);  	curl_easy_setopt (curl, CURLOPT_NOSIGNAL, true ); 	curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, false ); 	curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, false ); 	curl_easy_setopt (curl, CURLOPT_VERBOSE, false ); 	int  status_code = curl_easy_perform (curl); 	curl_easy_cleanup (curl); 	curl_slist_free_all (slist); 	Json::Value obj; 	if  (status_code != CURLcode::CURLE_OK) { 		obj["curl_error_code" ] = status_code; 		return  obj.toStyledString (); 	} 	 	JSONCPP_STRING error; 	Json::CharReaderBuilder builder; 	const  std::unique_ptr<Json::CharReader> reader (builder.newCharReader())  	reader->parse (response.data (), response.data () + response.size (), &obj, &error); 	std::string access_token = obj["access_token" ].asString (); 	return  access_token; } int  write_string_to_file_append (const  std::string & file_string, const  std::string str) 	std::ofstream OsWrite (file_string, std::ofstream::app)  ; 	OsWrite << str; 	OsWrite << std::endl; 	OsWrite.close (); 	return  0 ; } int  main (int  argc, char  *argv[]) 	std::string tokenKey; 	tokenKey = getTokenKey (); 	std::cout << "Token Key: "  << tokenKey << "\n" ; 	std::string filename = "tokenKey.db" ; 	write_string_to_file_append (filename, tokenKey); 	system ("pause" ); 	exit (EXIT_SUCCESS); } 
代码分析 std::string url = "https://aip.baidubce.com/oauth/2.0/token" ; std::string apikey = "这里更改为对应应用的 API Key" ; std::string secritkey = "这里更改为对应应用的 Secrit Key" ; std::map<std::string, std::string> params; std::string response; params["grant_type" ] = "client_credentials" ; params["client_id" ] = apikey; params["client_secret" ] = secritkey; for  (auto  it = params.begin (); it != params.end (); ++it) {    url += (it == params.begin () ? "?"  : "&" ) + it->first + "="  + it->second; } 
上面这段代码主要用于获取最终的请求 URL。因为这里使用的是 get 方法来获取 access token,所以需要将所有参数添加到 URL 中。params 用于存储请求参数,response 表示请求结果。for 循环则是将各个参数和 URL 使用 ? 和 & 连接起来。最终 URL 的一个示例如下:
https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=Va5yQRHlA4Fq5eR3LT0vuXV4&client_secret=0rDSjzQ20XUj5itV6WRtznPQSzr5pVw2& 
CURL *curl = curl_easy_init (); struct  curl_slist  * slist = NULL ;curl_easy_setopt (curl, CURLOPT_URL, url.c_str ());curl_easy_setopt (curl, CURLOPT_HTTPHEADER, slist);curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writeCallback);  curl_easy_setopt (curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt (curl, CURLOPT_NOSIGNAL, true );curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, false );curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, false );curl_easy_setopt (curl, CURLOPT_VERBOSE, false );int  status_code = curl_easy_perform (curl);curl_easy_cleanup (curl);curl_slist_free_all (slist);
上面这段代码主要是对 URL 请求进行设置,并请求,结果通过回调函数返回给 response。关于这里面的部分函数的使用方法可以参考:The Easy interface 
curl_easy_init 函数必须是第一个要调用的函数,并且它返回一个 CURL 类型的简易句柄,必须将该 CURL 简易句柄用作 easy 接口中其他函数的输入。
curl_easy_setopt 用来告诉libcurl如何表现。通过设置适当的选项,应用程序可以更改libcurl的行为。这里设置的几个参数解释如下:
更多 Curl 的 options 参考 curl_easy_setopt 。
size_t  writeCallback (void  *ptr, size_t  size, size_t  nmemb, void  *userdata) 	std::string *str = dynamic_cast <std::string *>((std::string *)userdata); 	str->append ((char  *)ptr, size * nmemb); 	return  size * nmemb; } 
上面这段代码是回调函数,一旦收到需要保存的数据,libcurl 就会立即调用此回调函数。对于大多数传输,此回调将被调用多次,每次调用都会传递另一块数据。ptr 指向传递的数据,该数据的大小为 nmemb;大小始终为 1。关于该函数的使用说明可以参考 CURLOPT_WRITEFUNCTION explained  和 getinmemory.c 。
Json::Value obj; if  (status_code != CURLcode::CURLE_OK) {    obj["curl_error_code" ] = status_code;     return  obj.toStyledString (); } JSONCPP_STRING error; Json::CharReaderBuilder builder; const  std::unique_ptr<Json::CharReader> reader (builder.newCharReader()) reader->parse (response.data (), response.data () + response.size (), &obj, &error); std::string access_token = obj["access_token" ].asString (); 
上面这段代码主要将字符串转换为 Json 格式,然后获取 access_token 值。
另外我们在调用接口获取到 access token 后,可以将其存储到文件中,因为每个 access token 的有效期为 30 天,所以可以重复使用直到过期。以下代码为将字符串写入文件和从文件读入。
int  writeFile (const  std::string & fileString, const  std::string &str)  	std::ofstream out (fileString, std::ios::binary)  ; 	if  (out.is_open ()) { 		out << str; 		out.close (); 	} 	return  0 ; } int  readFile (const  std::string & fileString, std::string &str)  	std::ifstream in (fileString)  ; 	if  (!in.is_open ()) { 		str = "" ; 		return  -1 ; 	} 	char  buffer[256 ]; 	while  (!in.eof ()) { 		in.getline (buffer, sizeof (buffer));	 	} 	str = buffer;     return  0 ; }