Linux系统的附加要求(GNU编译器集合(GCC)4.9或更高版本)
(官方教程https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/setup.html和
http://sdk.amazonaws.com/cpp/api/LATEST/index.html)
要编译在Linux上,您必须具备的头文件(-dev
包)为libcurl
,libopenssl
, libuuid
,zlib
,和可选,libpulse
亚马逊波利支持。通常,您可以在系统的包管理器中找到包。
在基于Debian / Ubuntu的系统上安装这些软件包
sudo apt-get install libcurl4-openssl-dev libssl-dev uuid-dev zlib1g-dev libpulse-dev
在基于Redhat / Fedora/Centos的系统上安装这些软件包
sudo yum install libcurl-devel openssl-devel libuuid-devel pulseaudio-devel
1.源码包下载地址
2.cmake不得低于3.0(可以到官网下载安装)
3.创建一个用于创建构建文件的目录,并在其中生成必要的构建文件。
mkdir sdk_build
cd sdk_build
cmake <path/to/sdk/source>
4.生成makefile文件
cmake -DCMAKE_BUILD_TYPE=Release /usr/local/aws-sdk-cpp-master -DOPENSSL_ROOT_DIR=/usr/local/openssl
//-DCMAKE_BUILD_TYPE 指定编译的版本
//随后指定makefile生成的目录
//-DOPENSSL_ROOT_DIR指定openssl的主目录(国内一些产品更改了s3的签名算法,修改了他的签名用到了openssl)
5.修改cmake生成的配置文件要去掉 -Werror 参数(将警告视为错误)
进入cmake生成makefile的目录:
去掉核心模块vi aws-cpp-sdk-core/CMakeFiles/aws-cpp-sdk-core.dir/flags.make 去掉-Werror
修改s3模块配置vi aws-cpp-sdk-s3/CMakeFiles/aws-cpp-sdk-s3.dir/flags.make 去掉-Werror
其它模块与之类似
6.编译自己所需要的模块(不建议全部编译,亚马逊这整个工程太大了,包含的东西很多可能用不到,而且这样很耗时,但aws-cpp-sdk-core核心模块必须先编译了再去编译你所需要的模块)
编译命令:
编译aws-cpp-sdk-core
make -j `nproc` -C aws-cpp-sdk-core
make install DESTDIR=/usr/local/inphase/aws -C aws-cpp-sdk-core
编译aws-cpp-sdk-s3
make -j `nproc` -C aws-cpp-sdk-s3
make install DESTDIR=/devinphase/inphase/aws -C aws-cpp-sdk-s3
其它与之类似
(make参数可参考http://man.linuxde.net/make)`nproc`参数是取当前cpu的核数
亚马逊c++验证算法修改
auth目录:签名验证相关;
client目录:亚马逊客户端请求实例,所有的s3内的所有请求都需要实例化这个client
config目录:加载配置文件,签名时可以将一些配置写入一个文件通过这个配置文件加载器来加载;这个官方推荐的做法;
external目录:亚马逊封装的JsonCpp 和tinyxml第三方库,很多地方使用到这2个库
http目录:封装了cul和Windows平台的winhttp用于http跨平台
internal目录:http资源获取的类
platform目录:平台相关
utils目录:一些些见名知意的工具类
AWSAuthSigner抽象类定义签名验证必须实现的接口
AWSAuthV4Signer类继承自AWSAuthSigner实现AWSAuthSigner所有接口,这个是亚马逊通用的v4签名验证方式
AWSNullSigner类继承自AWSAuthSigner但它什么都没做,就是明文不签名验证
TelecomOOSSigner类继承自AWSAuthSigner实现AWSAuthSigner所有接口,这个是自己定制的修改了签名的方式,以适用于国内某平台的签名标准,使用了openssl库
代码如下:
bool TelecomOOSSigner::SignRequest(Aws::Http::HttpRequest& request, bool signBody) const
{
AWSCredentials credentials = m_credentialsProvider->GetAWSCredentials();
//don't sign anonymous requests
if (credentials.GetAWSAccessKeyId().empty() || credentials.GetAWSSecretKey().empty())
{
return true;
}
if (!credentials.GetSessionToken().empty())
{
request.SetAwsSessionToken(credentials.GetSessionToken());
}
Aws::String payloadHash;
switch (m_payloadSigningPolicy)
{
case PayloadSigningPolicy::Always:
signBody = true;
break;
case PayloadSigningPolicy::Never:
signBody = false;
break;
case PayloadSigningPolicy::RequestDependent:
// respect the request setting
default:
break;
}
if (signBody /*|| "binary/octet-stream" != request.GetContentType().c_str()*/ )
{
payloadHash.assign(ComputePayloadHash(request));
if (payloadHash.empty())
{
return false;
}
}
else
{
AWS_LOGSTREAM_DEBUG(v4LogTag, "Note: Http payloads are not being signed. signPayloads=" << signBody
<< " http scheme=" << Http::SchemeMapper::ToString(request.GetUri().GetScheme()));
}
//calculate date header to use in internal signature (this also goes into date header).
DateTime now = GetSigningTimestamp();
Aws::String dateHeaderValue = now.ToGmtString(OOSLONG_DATE_FORMAT_STR);
request.SetDate(dateHeaderValue);
Aws::StringStream signedHeadersStream;
signedHeadersStream << HttpMethodMapper::GetNameForHttpMethod(request.GetMethod());
signedHeadersStream << NEWLINE;
//resourcePath
Aws::String strBucket = request.GetHeaders().at("host");
auto pos = strBucket.find(".");
strBucket.erase(strBucket.begin() + pos, strBucket.end());//bucket
Aws::String strurls = request.GetUri().GetPath();//urlpath
strurls.erase(0, 1);
Aws::String resourcePath =
"/" +
((!strBucket.empty()) ? strBucket : "") +
((! strurls.empty()) ? strurls : "/");
const Aws::String startsWith = "x-amz-";
HeaderValueCollection reqHeader = request.GetHeaders();
HeaderValueCollection interestingHeaders;
if ( ! reqHeader.empty() && reqHeader.size() >0 )
{
for (auto iter : reqHeader)
{
Aws::String key = iter.first;
Aws::String value = iter.second;
if (key.empty()) continue;
key = Aws::Utils::StringUtils::ToLower(key.c_str());
// Ignore any headers that are not particularly interesting.
if (key == "content-type" || key == "content-md5" || key == "date" || (key.compare(0, startsWith.length(), startsWith) == 0)
)
{
interestingHeaders.insert(std::make_pair(key, value));
}
}
}
// Remove default date timestamp if "x-amz-date" is set.
auto iter = interestingHeaders.find("x-amz-date");
if (iter != interestingHeaders.end()) {
iter->second = "";
}
// These headers require that we still put a new line in after them,
// even if they don't exist.
if ( interestingHeaders.find("content-type") == interestingHeaders.end()) {
interestingHeaders.insert(std::make_pair("content-type", ""));
}
if (interestingHeaders.find("content-md5") == interestingHeaders.end()) {
interestingHeaders.insert(std::make_pair("content-md5", ""));
}
for (auto parameter : reqHeader)
{
if (parameter.first.compare(0, startsWith.length(), startsWith) == 0)
{
interestingHeaders.insert(std::make_pair(parameter.first, parameter.second));
}
}
// Add all the interesting headers (i.e.: all that startwith x-amz- ;-))
for (auto paramerEntry : interestingHeaders)
{
Aws::String key =paramerEntry.first;
Aws::String value = paramerEntry.second;
if (paramerEntry.first.compare(0, startsWith.length(), startsWith) == 0)
{
signedHeadersStream << paramerEntry.first.c_str() << ":" << paramerEntry.second.c_str() << NEWLINE;
}
else
{
signedHeadersStream << paramerEntry.second.c_str() << NEWLINE;
}
}
//Add all the interesting parameters
signedHeadersStream << resourcePath;
QueryStringParameterCollection paramers = request.GetQueryStringParameters();
std::vector<Aws::String> parameterNames;
for (auto paramer : paramers)
{
parameterNames.push_back(paramer.first) ;
}
std::sort(parameterNames.begin(), parameterNames.end(),std::less<Aws::String>());
Aws::String strSeparator("?");
std::set<Aws::String>::iterator iters;
for(auto parameterName : parameterNames)
{
iters = m_canonicalizedResource.find(parameterName);
if (iters == m_canonicalizedResource.end()) {
continue;
}
signedHeadersStream << strSeparator;
signedHeadersStream << parameterName;
Aws::String parameterValue = paramers.find(parameterName)->second;
if (! parameterValue.empty())
{
signedHeadersStream << parameterValue;
}
strSeparator = "&";
}
//calculate signed headers parameter
Aws::String signedHeadersValue = signedHeadersStream.str();
AWS_LOGSTREAM_DEBUG(v4LogTag, "Signed value:" << signedHeadersValue);
//now compute HMAC-SHA1 on that request string
//CHMAC_SHA1 hmac;
typedef unsigned char BYTE;
//unsigned char sigval[256];
unsigned char * sigval = nullptr;
unsigned int iHmacLength = 0;
HmacEncode((const char *)credentials.GetAWSSecretKey().c_str(), credentials.GetAWSSecretKey().length(), (const char *)signedHeadersValue.c_str(), signedHeadersValue.length(),sigval, iHmacLength);
ByteBuffer message(sigval, iHmacLength);
Aws::String cannonicalRequestHash = HashingUtils::Base64Encode(message);
// cannonicalRequestHash = URI::URLEncodePath(cannonicalRequestHash);
if (sigval) {
free(sigval);
cout << "hmac is freed!" << endl;
}
Aws::StringStream ss;
ss << cannonicalRequestHash;
auto awsAuthString = ss.str();
std::cout << "hmac :" << awsAuthString << std::endl;
AWS_LOGSTREAM_DEBUG(v4LogTag, "Signing request with: " << awsAuthString);
request.SetAwsAuthorization("AWS " + credentials.GetAWSAccessKeyId() + ":" + awsAuthString);
return true;
}