.NET手记-友盟消息推送服务器端加密算法的实现
2015-08-05 16:52
351 查看
最近为App开发消息推送功能,这里我们采用了友盟的消息推送服务,但其后台简陋,可定制化程度低,所以决定接入服务器端API,在自己的服务器上部署一套推送服务。
其中涉及到很多问题,首先要解决的就是与友盟服务器的加密验证问题。
[b]官方示例[/b]
友盟官方的加密算法使用Python实现的,核心是MD5算法,如下:
Python程序输出结果为:
561128496d0f7a2acc098eb0ac263bd3
![](http://images0.cnblogs.com/blog2015/599309/201508/051610143762760.png)
[b]问题描述[/b]
简单一看发现很简单,于是使用C#实现了对应的一套算法,然而实际运行结果却大相径庭,让人困惑,如下:
运行之后我们发现输出结果为:
显然这两个结果是不对的,是无法通过友盟服务器验证的,那到底是什么问题导致的呢?
[b]问题分析[/b]
首先我们检查了自己的MD5加密算法和文本编码,确认了在使用同样输入字符串的情况下输出是一致的,效果与python中md5.hexdigest()、Java中DigestUtils.md5Hex(String)函数输出的结果是一致的,那么可以先确定我们的MD5算法是对的,如下:
那么剩余的问题就是,是否是我们的输入字符串有问题?于是我分别输出拼接出的输入字符串做了对比,如下:
仔细对比之后,发现了3点区别:
1.Python生成的字符串post_body部分采用了Unicode编码,而c#则是默认编码
2.Python生成的字符串post_body部分“:”和“,”之后都有空格,格式与c#采用json序列化后的字符串格式不一致
3.Python生成的字符串post_body部分键值对的顺序与c#生成的不一致
[b]问题解决[/b]
首先我们使用c#将字符串中post_body部分转成Unicode编码,再将相应键值的位置调整为和Python生成的一致,最后再将缺失的空格添加今日字符串中,完整的程序如下:
这样就能使得c#程序输出和官方python demo一样的结果了。
![](http://images0.cnblogs.com/blog2015/599309/201508/051642074081151.png)
[b]总结[/b]
下面会进一步的进行与友盟消息推送服务的集成,进一步验证此方案的有效性,若有较好方案,欢迎指教,不甚感激
其中涉及到很多问题,首先要解决的就是与友盟服务器的加密验证问题。
[b]官方示例[/b]
友盟官方的加密算法使用Python实现的,核心是MD5算法,如下:
import hashlib import json def md5(s): print s m = hashlib.md5(s) return m.hexdigest() appkey = '你的appkey' app_master_secret = '你的app_master_secret' timestamp = '你的timestamp' device_token='21321321321321' method = 'POST' url = 'http://msg.umeng.com/api/send' params = {'appkey': appkey, 'timestamp': timestamp, 'device_tokens': device_token, 'type': 'unicast', 'payload': {'body': {'ticker': 'Hello World', 'title':'你好', 'text':'来自友盟推送', 'after_open': 'go_app'}, 'display_type': 'notification' } } post_body = json.dumps(params) print post_body sign = md5('%s%s%s%s' % (method,url,post_body,app_master_secret))
Python程序输出结果为:
561128496d0f7a2acc098eb0ac263bd3
![](http://images0.cnblogs.com/blog2015/599309/201508/051610143762760.png)
[b]问题描述[/b]
简单一看发现很简单,于是使用C#实现了对应的一套算法,然而实际运行结果却大相径庭,让人困惑,如下:
private string GetSign() { var param = new { appkey = "你的appkey", timestamp = "你的timestamp", device_tokens = "21321321321321", type = "unicast", payload = new { body = new { ticker = "Hello World", title = "你好", text = "来自友盟推送", after_open = "go_app" }, display_type = "notification" } }; var app_master_secret = "你的app_master_secret"; var method = "POST"; var url = "http://msg.umeng.com/api/send"; var serializer = JsonSerializer.Create(); var jsonWriter = new System.IO.StringWriter(); serializer.Serialize(jsonWriter, param); var post_body = jsonWriter.ToString(); var str = method + url + post_body + app_master_secret; var sign = MD5(str); return sign; } private string MD5(string s) { var x = new MD5CryptoServiceProvider(); byte[] bs = System.Text.Encoding.UTF8.GetBytes(s); bs = x.ComputeHash(bs); var str = new System.Text.StringBuilder(); foreach (byte b in bs) { str.Append(b.ToString("x2").ToLower()); } return str.ToString(); }
运行之后我们发现输出结果为:
244ba68e49004f7b4ccdaf9bae617296
显然这两个结果是不对的,是无法通过友盟服务器验证的,那到底是什么问题导致的呢?
[b]问题分析[/b]
首先我们检查了自己的MD5加密算法和文本编码,确认了在使用同样输入字符串的情况下输出是一致的,效果与python中md5.hexdigest()、Java中DigestUtils.md5Hex(String)函数输出的结果是一致的,那么可以先确定我们的MD5算法是对的,如下:
private string MD5(string s) { var x = new MD5CryptoServiceProvider(); var bs = System.Text.Encoding.UTF8.GetBytes(s); bs = x.ComputeHash(bs); var str = new System.Text.StringBuilder(); foreach (byte b in bs) { str.Append(b.ToString("x2").ToLower()); } return str.ToString(); }
那么剩余的问题就是,是否是我们的输入字符串有问题?于是我分别输出拼接出的输入字符串做了对比,如下:
//Python生成的拼接字符串 POSThttp://msg.umeng.com/api/send{"appkey": "\u4f60\u7684appkey", "timestamp": "\u4f60\u7684timestamp", "device_tokens": "21321321321321", "type": "unicast", "payload": {"body": {"text": "\u6765\u81ea\u53cb\u76df\u63a8\u9001", "after_open": "go_app", "ticker": "Hello World", "title": "\u4f60\u597d"}, "display_type": "notification"}}你的app_master_secret //c#生成的拼接字符串 POSThttp://msg.umeng.com/api/send{"appkey":"你的appkey","timestamp":"你的timestamp","device_tokens":"21321321321321","type":"unicast","payload":{"body":{"ticker":"Hello World","title":"你好","text":"来自友盟推送","after_open":"go_app"},"display_type":"notification"}}你的app_master_secret
仔细对比之后,发现了3点区别:
1.Python生成的字符串post_body部分采用了Unicode编码,而c#则是默认编码
2.Python生成的字符串post_body部分“:”和“,”之后都有空格,格式与c#采用json序列化后的字符串格式不一致
3.Python生成的字符串post_body部分键值对的顺序与c#生成的不一致
[b]问题解决[/b]
首先我们使用c#将字符串中post_body部分转成Unicode编码,再将相应键值的位置调整为和Python生成的一致,最后再将缺失的空格添加今日字符串中,完整的程序如下:
private string GetSign()
{
var param = new
{
appkey = "你的appkey",
timestamp = "你的timestamp",
device_tokens = "21321321321321",
type = "unicast",
payload = new
{
body = new
{
text = "来自友盟推送",
after_open = "go_app",
ticker = "Hello World",
title = "你好"
},
display_type = "notification"
}
};
var app_master_secret = "你的app_master_secret";
var method = "POST";
var url = "http://msg.umeng.com/api/send";
var serializer = JsonSerializer.Create();
var jsonWriter = new System.IO.StringWriter();
serializer.Serialize(jsonWriter, param);
var post_body = jsonWriter.ToString();
post_body = unicode_js_0(post_body).Replace(":",": ").Replace(",",", ");
var str = method + url + post_body + app_master_secret;
var sign = MD5(str);
return sign;
}
/// <summary>
/// MD5加密
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private string MD5(string s) { var x = new MD5CryptoServiceProvider(); var bs = System.Text.Encoding.UTF8.GetBytes(s); bs = x.ComputeHash(bs); var str = new System.Text.StringBuilder(); foreach (byte b in bs) { str.Append(b.ToString("x2").ToLower()); } return str.ToString(); }
/// <summary>
/// 中文转unicode(符合js规则的)
/// </summary>
/// <returns></returns>
public string unicode_js_0(string str)
{
var outStr = string.Empty;
if (!string.IsNullOrEmpty(str))
{
for (int i = 0; i < str.Length; i++)
{
if (Regex.IsMatch(str[i].ToString(), @"[\u4e00-\u9fa5]")) { outStr += "\\u" + ((int)str[i]).ToString("x"); }
else { outStr += str[i]; }
}
}
return outStr;
}
这样就能使得c#程序输出和官方python demo一样的结果了。
![](http://images0.cnblogs.com/blog2015/599309/201508/051642074081151.png)
[b]总结[/b]
下面会进一步的进行与友盟消息推送服务的集成,进一步验证此方案的有效性,若有较好方案,欢迎指教,不甚感激
相关文章推荐
- 测试工程师(QA)必知必会的测试工具
- HDOJ1342lotto(DFS)
- Courses
- C++沉思录 第八章 面向对象程序范例
- .net 如何在后台添加控件,并获取值。
- 红头文件
- android 3G移植
- SylixOS 经得起检验的国产操作系统 (六)
- system.cpp
- 【POJ 2151】Check the difficulty of problems
- Web API with OAuth2.0
- Collection集合的总结以及如果选择适合的集合(包括对List和Set的对比)
- 使用CSS绘制星级评分效果的方法
- 一个简单了解spring的例子
- java正则表达式特殊字符转义
- CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\e6148660
- system.h
- hdu 1728 逃离迷宫
- 学院,系别,班级,学生XXX.hbm.xml配置
- POJ 3069 Saruman's Army