zoukankan      html  css  js  c++  java
  • (基础篇 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"
    }
    
    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>
    
    
    // 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 << "
    ";
    	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_URL URL to work on
    CURLOPT_HTTPHEADER Custom HTTP headers
    CURLOPT_WRITEFUNCTION Callback for writing data
    CURLOPT_WRITEDATA Data pointer to pass to the write callback
    CURLOPT_NOSIGNAL Do not install signal handlers
    CURLOPT_SSL_VERIFYPEER Verify the SSL certificate
    CURLOPT_SSL_VERIFYHOST Verify the host name in the SSL certificate
    CURLOPT_VERBOSE Display 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;
    }
    
  • 相关阅读:
    jmeter jsr223脚本引用变量的问题
    apk反编译
    JS时间对像
    无缝滚动
    带详情图片轮播
    飘动文字2
    飘动的文字1
    抖动图片2
    点击图片图片上下抖动
    点击div掉下和上升
  • 原文地址:https://www.cnblogs.com/busyboxs/p/12245415.html
Copyright © 2011-2022 走看看