中国天气预报接口:SmartWeather API中key的计算方法

最近申请到SmartWeatherAPI天气预报接口的使用权限,开始着手我的实时天气预报系统的开发,主要开发的版本使用的是Python脚本,成果将于近期以系列文章与大家见面。今天在这里我和大家探讨一下SmartWeatherAPI中key的计算方法,并提供C++程序源码供大家参考。

开发环境: Ubuntu + GCC4.7

零、 SmartWeather API的申请

SmartWeatherAPI(简称“SWA接口”)是中国气象局面向网络媒体、手机厂商、第三方气象服务机构等用户,通过web方式提供数据气象服务的官方载体。是国内首个面向个人网站、开发爱好者和服务机构的气象服务API数据开发接口(申请地址戳着里)。申请过程需要填写一个表格,发送到官方邮箱,人工审核通过后会回复邮件,随信提供appid和private_key等信息。

回复邮件部分内容如下(appid和private_key为私密信息,故用红色横线代替):

您好:
    恭喜您的申请已通过审核,以下是为您分配的鉴权信息:
    appid:--------------
    private_key:------------------------
    接口使用说明请参考《SmartWeatherAPI_Lite_WebAPI 版产品使用说明书》,区域列表:请见附件areaid_list.xlsx。
    该鉴权信息仅限您个人或本公司使用,如有泄露我们将撤销您的使用权限,必要时将追究相关责任。
    最后,非常感谢您的参与。

一、 WebAPI接口说明书

接口说明说在上面所提到的API接口申请的网站可以下载到,下面就起说明书中几个要点做以下说明:

1. 接口说明

请求方式: http get

接口组成: 由固定 URL 加 5 个不同的参数组成,完整URL需客户端经过固定方式加密后使用

数据返回: json

完整URL: http://webapi.weather.com.cn/data/?areaid=""&type=""&date=""&appid=""&key=".urlencode($key)

输入参数:

areaid: 区域id,审核通过后邮件中有个附件,提供的就是现有的所有区域的id号。

type: 数据类型(实况: observe, 指数: index, 常规预报: forecast3d)。

date: 客户端日期,按照格式yyyyMMddHHmm获取客户端当前时间。

appid: 固定分配的型号标识,审核通过后邮件告知(传递参数时:截取 appid 的前 6 位; 生成公钥时:取完整的 appid)。

key: 令牌,有公钥(public_key)和私钥(private_key)通过固定算法加密生成。

2. 加密方式

加密算法是今天博客的基础,大家仔细阅读。加密算法中涉及到的三个要素分别为:

  • private_key: 审核通过后,邮件中会提供。private_key仅负责与 public_key 共同合成 key 传参,私钥不可见,客户端与服务端各存储一份;
  • public_key: 不包含key在类的完整URL的其他部分(此处appid为完整appid);
  • key的算法: 说明书中提供的是php中的算法代码,如下
  • 1 key = base64_encode(hash_hmac('sha1', $public_key, $private_key, TRUE));

    key加密后,通过 urlencode 对其编码后传参。

举例说明,除去key部分的URL如下:

http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads

私钥private_key假设为: private_key

我们使用上述算法首先计算出加密后的key,得到key之后使用urlencode方法处理我们加密得到的key,结果为:

A%2Fp2QJ4R%2FD3FFCr6XwUCyNP56Y0%3D

则我们最后的输入URL为:

http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61&key=A%2Fp2QJ4R%2FD3FFCr6XwUCyNP56Y0%3D

3. 返回数据

输出实例:

 1 {
 2     "l" : 
 3     {
 4         "l1" : "14",
 5         "l2" : "46",
 6         "l3" : "2",
 7         "l4" : "6",
 8         "l7" : "12:00"
 9     }
10 }

其中:

l1: 表示当前温度(摄氏度);

l2: 表示当前湿度(%);

l3: 表示当前风力(级);

l4: 表示当前风向编号(主页有文献可以查到具体的风向);

l7: 表示实况发布时间。

当前不同的type请求结果是大相径庭的,具体的其他2类的我在这里不一一说明,需要了解的童鞋可以参考官方的文档,这里顺便列举一个type=forecast3d的返回结果:

 1 {
 2     "c" : 
 3     {
 4         "c1" : "101270101",
 5         "c10" : "1",
 6         "c11" : "028",
 7         "c12" : "610000",
 8         "c13" : "104.071",
 9         "c14" : "30.67",
10         "c15" : "507",
11         "c16" : "AZ9280",
12         "c17" : "+8",
13         "c2" : "chengdu",
14         "c3" : "成都",
15         "c4" : "chengdu",
16         "c5" : "成都",
17         "c6" : "sichuan",
18         "c7" : "四川",
19         "c8" : "china",
20         "c9" : "中国"
21     },
22     "f" : 
23     {
24         "f0" : "201401241100",
25         "f1" : 
26         [
27             
28             {
29                 "fa" : "01",
30                 "fb" : "01",
31                 "fc" : "16",
32                 "fd" : "2",
33                 "fe" : "4",
34                 "ff" : "4",
35                 "fg" : "0",
36                 "fh" : "0",
37                 "fi" : "07:59|18:32"
38             },
39             
40             {
41                 "fa" : "01",
42                 "fb" : "01",
43                 "fc" : "16",
44                 "fd" : "2",
45                 "fe" : "4",
46                 "ff" : "4",
47                 "fg" : "0",
48                 "fh" : "0",
49                 "fi" : "07:58|18:33"
50             },
51             
52             {
53                 "fa" : "01",
54                 "fb" : "02",
55                 "fc" : "14",
56                 "fd" : "4",
57                 "fe" : "4",
58                 "ff" : "4",
59                 "fg" : "0",
60                 "fh" : "0",
61                 "fi" : "07:58|18:34"
62             }
63         ]
64     }
65 }
View Code

二、 加密过程分析

在动手实现加密方法之前,我在想,首先我应该知道正确的加密结果撒,让我看到正确的返回数据之后再去做这件事情不是更有意义。看官方提供的是php的方法,那我就先用php试一下呗,可我没有安装php阿,总不能因为做个小测试还整个php环境吧,麻烦!幸好有php online帮到我http://writecodeonline.com/php/

上面实例中的结果就是这么来的:

1 echo urlencode(base64_encode(hash_hmac('sha1', "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads", "private_key", TRUE)));

当然,实例中的URL是不会返回正确数据的,因为我们用的appid和private_key都是假造的,我在测试的过程使用的是我申请到的相关信息。

结果返回成功了,我们开始分析如何使用C++去实现这个加密过程吧!

1. 肢解加密过程

一口吃不成一个胖子,我们一步一步来,从最内层开始,从hash_hmac入手,说白了不就是hash过程了,这时候我想到了openssl,是的,就是他了!首先我们在php环境中求出我们这一步的结果再说:

1 echo hash_hmac('sha1', "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads", "private_key", TRUE);

结果如下:

1 �v@��=�*�_�����

使用openssl之前,让我们分析以下php中的hash_hmac函数中的几个参数,前三个估计一目了然,最后一个是什么意思呢?函数原型如下:

1 string hash_hmac( string $algo , string $data , string $key [, bool $raw_output = false ] )

最后一个参数raw_output解释为: When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.

好了,我们开始用openssl试试,先不着急用C++,先在bash下用command试试:

1 echo -n "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads" | openssl dgst -sha1 -binary -hmac "private_key"

看到这里的-binary参数没有,这就是我之前为什么为专门分析hash_hmac最后一个参数的原因,因为我当时就在这里少了-binary参数,导致出来的结果老是对不上。好了,结果表明,和php的结果一致。

继续肢解,开始第二步,base64_encode函数的分析,同样, 先在php中来过:

1 echo base64_encode(hash_hmac('sha1', "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads", "private_key", TRUE));

结果如下:

1 A/p2QJ4R/D3FFCr6XwUCyNP56Y0=

我们来看看base64_encode函数的原型:

1 string base64_encode ( string $data )

这个函数,见名知意,就是对数据进行base64编码。在linux下有现成的工具,即base64:

1 echo -n "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads" | openssl dgst -sha1 -binary -hmac "private_key" | base64

测试通过,我们开始最后一步,urlencode函数做什么,这个问题在之前一篇文章:http://www.cnblogs.com/berlin-sun/p/translateonline.html 中提到过,其实就是对url重新进行编码,Returns a string in which all non-alphanumeric characters except -_. have been replaced with a percent (%) sign followed by two hex digits and spaces encoded as plus (+) signs.

2. 具体实现

hmac过程:

1 #include <openssl/hmac.h>
2 
3 unsigned char *digest;
4 digest = HMAC(EVP_sha1(), key, strlen(key), (unsigned char*)weather_api, strlen(weather_api), NULL, NULL);

base64过程:

 1 #include <openssl/bio.h>
 2 #include <openssl/buffer.h>
 3 
 4 char *base64(const unsigned char* input, int length)
 5 {
 6     BIO *bmem, *b64;
 7     BUF_MEM *bptr;
 8 
 9     b64 = BIO_new(BIO_f_base64());
10     bmem = BIO_new(BIO_s_mem());
11     b64 = BIO_push(b64, bmem);
12     BIO_write(b64, input, length);
13     BIO_flush(b64);
14     BIO_get_mem_ptr(b64, &bptr);
15     
16     char *buff = (char *)malloc(bptr->length);
17     memcpy(buff, bptr->data, bptr->length-1);
18     buff[bptr->length-1] = 0;
19 
20     BIO_free_all(b64);
21 
22     return buff;
23 }
24 
25 
26 char *base64Digest = base64(digest, strlen((char *)digest));

urlencode过程:

1 #inlcude “curl/curl.h”
2 
3 CURL * curl;
4 curl = curl_easy_init();
5 
6 char *encode_key = curl_easy_escape(curl, base64Digest, 0);

目前,C++程序就完成了这些,结果已经成功返回,如下图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值