我到处都在搜索此代码,但是找不到一个像样的代码。如何使用Amazon AWS S3访问GSOAP服务?

最佳答案

下面的代码来自OP。最初,该帖子既包含问题,也包含答案,我将其转换为问答格式。

签名必须采用以下格式

base64encode((HMAC-SHA1(ActionName+"AmazonS3"+XMLTimestamp)))

HMAC,SHA1和B64实用程序在以下位置可用
openssl

SOAP请求的格式由
wsdl

REST接口(interface)是不同的。

wsdl2h之后生成头,在soapcpp2之后生成GSOAP
客户端代码以下将是访问服务的代码:

要求:OpenSSLGSOAP

使用编译器预处理程序指令WITH_OPENSSL进行构建。连结
libeay32ssleay32
#include "AmazonS3SoapBinding.nsmap" //generated from soapcpp2
#include "soapAmazonS3SoapBindingProxy.h" //generated from soapcpp2
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>

/* convert to base64 */
std::string base64_encodestring(char* text, int len) {
    EVP_ENCODE_CTX ectx;
    int size = len*2;
    size = size > 64 ? size : 64;
    unsigned char* out = (unsigned char*)malloc( size );
    int outlen = 0;
    int tlen = 0;

    EVP_EncodeInit(&ectx);
    EVP_EncodeUpdate(&ectx,
            out,
            &outlen,
            (const unsigned char*)text,
            len
            );
    tlen += outlen;
    EVP_EncodeFinal( &ectx, out+tlen, &outlen );
    tlen += outlen;

    std::string str((char*)out, tlen );
    free( out );
    return str;
}

/* return the utc date+time in xml format */
const char* xml_datetime() {

  /*"YYYY-mm-ddTHH:MM:SS.000Z\"*/
  const int MAX=25;
  static char output[MAX+1];
  time_t now = time(NULL);

  strftime( output, MAX+1, "%Y-%m-%dT%H:%M:%S.000Z", gmtime( &now ) );

  std::cout <<output<<std::endl;
  return output;
}

/* first argument is the signing key */
/* all subsequent argumets are concatenated */
/* must end list with NULL */
char* aws_signature(char* key, ...) {
  unsigned int i, len;
  char *data, **list = &key;

  static char hmac[EVP_MAX_MD_SIZE];

  for (i = 1, len = 0; *(list+i) != NULL; ++i) {
    len += strlen( *(list+i) );
  }

  data = (char*)malloc(sizeof(char) * (len+1));

  if (data) {
    for ( i = 1, len = 0 ; *(list+i) != NULL ; ++i ) {
      strncpy( data+len, *(list+i), strlen(*(list+i)) );
      len += strlen(*(list+i));
    }
    data[len]='\0';

    std::cout<<data<<std::endl;
    HMAC( EVP_sha1(),
          key,  strlen(key),
          (unsigned char*)data, strlen(data),
          (unsigned char*) hmac, &len
        );
    free(data);
  }

  std::string b64data=base64_encodestring(hmac, len);

  strcpy(hmac,b64data.c_str());

  return hmac;
};

int main(void) {
   AmazonS3SoapBindingProxy client;

   soap_ssl_client_context(&client,
           /* for encryption w/o authentication */
           SOAP_SSL_NO_AUTHENTICATION,
           /* SOAP_SSL_DEFAULT | SOAP_SSL_SKIP_HOST_CHECK, */
           /* if we don't want the host name checks since
            * these will change from machine to machine */
           /*SOAP_SSL_DEFAULT,*/
           /* use SOAP_SSL_DEFAULT in production code */
           NULL,  /* keyfile (cert+key): required only when
                     client must  authenticate to server
                     (see SSL docs to create this file) */
           NULL,  /* password to read the keyfile */
           NULL,  /* optional cacert file to store trusted
                     certificates, use cacerts.pem for all
                     public certificates issued by common CAs */
           NULL,  /* optional capath to directory with trusted
                     certificates */
           NULL   /* if randfile!=NULL: use a file with random
                     data to seed randomness */
    );

    /* use this if you are behind a proxy server.....
        client.proxy_host="proxyserver"; // proxy hostname
        client.proxy_port=4250;
        client.proxy_userid="username";  // user pass if proxy
        client.proxy_passwd="password";  // requires authentication
        client.proxy_http_version="1.1"; // http version
    */
    _ns1__ListAllMyBuckets buk_req;
    _ns1__ListAllMyBucketsResponse buk_resp;
    ns1__ListAllMyBucketsResult buk_res;
    buk_res.soap=&client;

    buk_req.AWSAccessKeyId=new std::string("ACCESSKEY");
    buk_req.soap=&client;

    /* ListAllMyBuckets is the method I want to call here.
     * change it for other S3 services that you wish to call.*/

    char *sig=aws_signature(
            "SECRETKEY",
            "AmazonS3",
            "ListAllMyBuckets",
            xml_datetime(),
            NULL
            );


    buk_req.Signature=new std::string(sig);
    buk_req.Timestamp=new time_t(time(NULL));

    buk_resp.soap=&client;
    buk_resp.ListAllMyBucketsResponse=&buk_res;

    client.ListAllMyBuckets(&buk_req,&buk_resp);

    client.soap_stream_fault(std::cout);

    std::vector<ns1__ListAllMyBucketsEntry * >::iterator itr;

    for(itr=buk_resp.ListAllMyBucketsResponse->Buckets->Bucket.begin();
            itr!=buk_resp.ListAllMyBucketsResponse->Buckets->Bucket.end();
            itr++
            ) {
        std::cout<<(*itr)->Name<<std::endl;
    }

}

关于c++ - 如何使用适用于C和C++的GSOAP访问Amazon AWS S3?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7010703/

10-15 16:43