(基础篇 03)C++ 获取 access token

百度 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"
}
errorerror_description解释
invalid_clientunknown client idAPI Key不正确
invalid_clientClient authentication failedSecret Key不正确

C++ 代码

#include <curl/curl.h>
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <json/json.h>


// callback function for curl
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;
}

// get access token from server by get method
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;

	// append url with parameters
	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);  // set callback function
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // set var to receive return info from callback function
	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();
	}

	// parse json string
	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;
}

// write messages to file
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;

// append url with parameters
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);  // set callback function
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // set var to receive return info from callback function
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的行为。这里设置的几个参数解释如下:

options说明
CURLOPT_URLURL to work on
CURLOPT_HTTPHEADERCustom HTTP headers
CURLOPT_WRITEFUNCTIONCallback for writing data
CURLOPT_WRITEDATAData pointer to pass to the write callback
CURLOPT_NOSIGNALDo not install signal handlers
CURLOPT_SSL_VERIFYPEERVerify the SSL certificate
CURLOPT_SSL_VERIFYHOSTVerify the host name in the SSL certificate
CURLOPT_VERBOSEDisplay verbose information

更多 Curloptions 参考 curl_easy_setopt


// callback function for curl
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 explainedgetinmemory.c


Json::Value obj;
if (status_code != CURLcode::CURLE_OK) {
    obj["curl_error_code"] = status_code;
    return obj.toStyledString();
}

// parse json string
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;
}
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
本地服务获取access token的配置需要进行以下几个步骤: 1. 注册开发者账号并创建应用:首先,在CSDN开发者平台注册一个开发者账号,并创建一个应用。创建应用时,你会获得一对Client ID和Client Secret,这是用来获取access token的凭证。 2. 配置回调地址:在应用创建完成后,你需要配置一个回调地址。回调地址是在用户授权后重定向的URL,用于接收授权码。 3. 配置本地服务器:在本地服务器上,你需要创建一个接收回调请求的API端点。可以使用任何后端框架或库来创建一个HTTP服务,监听指定的端口,并处理来自CSDN的授权回调请求。 4. 接收授权码:当用户授权完成后,CSDN将会将授权码作为参数附加到回调URL中,然后重定向到你之前设置的回调地址。在你的本地服务器的API端点中,解析URL中的授权码。 5. 通过授权码获取access token:使用之前获取的授权码,向CSDN的Access Token URL发送一个POST请求,以获取access token。请求中需要包含Client ID、Client Secret、授权码以及其他必要的参数。 6. 存储和使用access token:一旦成功获取access token,将其存储在本地安全的位置。在每次使用CSDN API时,将access token作为Authorization头部的Bearer Token传递给API服务器。 请注意,保护好你的Client Secret和access token是非常重要的,不要将其泄露给其他人。另外,确保你的本地服务器是安全的,以防止未经授权的访问。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值