当前位置:首页 > 开发 > 编程语言 > 算法 > 正文

百度云推送javasdk诞生记之签名算法实现

发表于: 2013-06-22   作者:asialee   来源:转载   浏览次数:
摘要:         在实现之初,就遇到一个麻烦,因为每次调用服务器端都要进行验证,所以设计了一个签名算法,官方的文档如下:        签名算法 云推送服务API使用的签名算法如下: 获取请求的http method 获取请求的url,包括host和sheme,但不包括query_strin

        在实现之初,就遇到一个麻烦,因为每次调用服务器端都要进行验证,所以设计了一个签名算法,官方的文档如下:

      

签名算法

云推送服务API使用的签名算法如下:

  • 获取请求的http method
  • 获取请求的url,包括host和sheme,但不包括query_string的部分
  • 将所有参数(包括GET或POST的参数,但不包含签名字段)格式化为“key=value”格式,如“k1=v1”、“k2=v2”、“k3=v3”;
  • 将格式化好的参数键值对以字典序升序排列后,拼接在一起,如“k1=v1k2=v2k3=v3”,并将http method和url按顺序拼接在这个字符串前面;
  • 在拼接好的字符串末尾追加上应用的secret_key,并进行urlencode形成base_string;
  • 上述字符串的MD5值即为签名的值:
sign=MD5(urlencode($http_method$url$k1=$v1$k2=$v2$k3=$v3$secret_key)); 
说明:
$secret_key:通过“开发者中心 -> 管理中心 -> 点击某应用 -> 应用信息详情页” 获得。

举例:

url [POST]: 

http://{domain}/rest/2.0/channel/channel?method=token&timestamp=1313293563&expires=1313293565&v=1

   

 

         从官方文档来看,有几点是很重要的

  1.  http method参数是必须的,从rest api中发现,目前也只支持get和post
  2. host和scheme参数也是必须的,官方文档中说明支持https和http两种
  3. 签名字段不参加签名字段的生成
  4. 其他所有的参数按照key=value的方式拼成一个字符串
  5. 字符串末尾加上sk的值
  6. 将前面的字符串使用urlencode进行编码
  7. 将urlencode编码后的字符串生成md5值

       这个里面其他的地方都是没什么的,关键是参数的顺序,我们知道,客户端给服务器端提交参数的时候是没有顺序的,当时我在实现的时候发现,有一些方法的签名是对的,有一些被服务器端当成错误的签名了,琢磨不透参数的顺序是怎么样的,最后反复研究官方文档发现,参数的顺序是按照参数的字母顺序排列的。发现了这个,其他的都很简单了,直接上代码。

 

         

package com.baidu.push.auth;

/**
 * AK和SK是应用访问资源或服务的唯一凭证。 查看AK和SK信息
 * @see <a href="http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/guide">官方文档</a>
 * 
 * @author liyazhou@baidu.com
 *
 */
public class PushCredentials {

	private String accessKey;
	private String secretKey;

	public PushCredentials(String accessKey, String secretKey) {
		this.accessKey = accessKey;
		this.secretKey = secretKey;
	}

	public String getAccessKey() {
		return this.accessKey;
	}

	public String getSecretKey() {
		return this.secretKey;
	}
}

 PushCredentials这个里面是对ak和sk的一个简单封装,没有什么。

 

package com.baidu.push.auth;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.baidu.push.http.PushHttpRequest;
import com.baidu.push.reqeust.BaiduPushRequest;
import com.baidu.push.util.Constants;
import com.baidu.push.util.PushClientException;

/**
 * 生成签名算法
 * 
 * @see <a href="http://developer.baidu.com/wiki/index.php?title=docs/cplat/push/api">官方文档</a>
 * 
 * @author liyazhou@baidu.com
 *
 */
public class PushSigner {
	private static final Log log = LogFactory.getLog(PushSigner.class);
	
	private static String urlencode(String str) throws UnsupportedEncodingException {
		String rc = URLEncoder.encode(str, "utf-8");
		return rc.replace("*", "%2A");
	}
	
	public static void sign(BaiduPushRequest pushRequest,PushHttpRequest httpRequest, PushCredentials credentials) {
		StringBuilder signContents = new StringBuilder();
		// generate sign content
		if (null == pushRequest.getHttpMethod()) {
			throw new PushClientException("Sign failed! Param: httpMethod can not be empty!");
		}
		
		signContents.append(pushRequest.getHttpMethod().toString());
		if(pushRequest.isNeedSsl()){
			signContents.append(Constants.HTTPS);
		} else {
			signContents.append(Constants.HTTP);
		}
		signContents.append(Constants.PUSH_URL);
		
		if(pushRequest.getChannelId() == null){
			signContents.append(Constants.CHANNEL);
		} else {
			signContents.append(pushRequest.getChannelId());
		}
		Map<String,String> sinParameters = httpRequest.getParameters();
		for(Map.Entry<String, String> i : sinParameters.entrySet()) {
			signContents.append(i.getKey());
			signContents.append('=');
			signContents.append(i.getValue());
		}
		signContents.append(credentials.getSecretKey());
		log.info("signContents:"+signContents);
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.reset();
			//md.update( URLEncoder.encode(sb.toString(), "utf-8").getBytes() );
			md.update(urlencode(signContents.toString()).getBytes() );
			byte[] md5  = md.digest();
			
			signContents.setLength(0);
			for(byte b : md5) {
				signContents.append( String.format("%02x", b & 0xff));
			}
			
			httpRequest.addParameter("sign", signContents.toString());
		} catch (NoSuchAlgorithmException e) {
			log.error("error:"+e);
			throw new PushClientException("Sign failed! reason:"+e.getMessage());
		} catch (UnsupportedEncodingException e) {
			log.error("error:"+e);
			throw new PushClientException("Sign failed! reason:"+e.getMessage());
		}
	}
	
}

    

      PushSigner 这个类也很好理解,如果明白了签名算法,这个就是小case了,把这个留给广大同仁自己琢磨吧。

 

百度云推送javasdk诞生记之签名算法实现

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
花时间了研究了下百度云推送,自己写了一个sdk,其中也遇到一些问题,打算写一系列文章分享下写代码
花时间了研究了下百度云推送,自己写了一个sdk,其中也遇到一些问题,打算写一系列文章分享下写代码
百度云推送流程图: 百度云推送服务支持三种推送类型:通知、消息及富媒体;支持向所有用户、根据标
【阿里云产品公测】结构化数据服务OTS之JavaSDK初体验 作者:阿里云用户蓝色之鹰 一、OTS简单介绍 O
之前介绍过怎样使用shareSDK实现新浪微博分享功能,今天介绍怎样使用百度云推送SDK实现Android手机
消息推送-百度push 选择百度云推送理由:专业、稳定、免费(Google GCM在国内有时无法正常使用) 打
最近在做一个实时聊天软件的客户端,但是因为水平不足,自己写sorket会很蛋疼,于是采用了百度云推
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/27231237 现在app基本都有推
1.百度上创建开发者帐号 http://developer.baidu.com/ 2.登录后进入“开发者服务管理” 3.创建应用
1、去keychain生成csr文件(如果已经有了就不需要再生成了) 2、到开发者中心新建或者修改一个已经
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号