钉钉客户端JS-API权限签名算法.NET版
前段时间写了一篇博文《钉钉如何进行PC端开发》,在里面并未解决本地生成签名的问题,需要到官网进行生成,由于钉钉门票等认证信息会超期,因此,必须能本地用代码自动更新相关参数信息,来换取签名。官方文档由于这块并未有.NET版本的签名API可供调用,无奈只能自己摸索着进行实现。可笑的是,在看钉钉文档时候并未理解其算法,但是却在看微信JS-API签名生成算法的时候顿悟了。感觉二者这个权限体系认证很是类似。
话不多说,切入正题。
钉钉广泛文档对于JS-API的说明是这样的:
开发者在web页面使用钉钉容器提供的jsapi时,需要验证调用权限,并以参数signature标识合法性
签名生成的规则:
List keyArray = sort(noncestr,timestamp,jsapi_ticket,url);
String str = assemble(keyArray);
signature = sha1(str);
参与签名的字段包括在上文中获取的jsapi_ticket,noncestr(随机字符串,自己随便填写即可),timestamp(当前时间戳,具体值为当前时间到1970年1月1号的秒数),url(当前网页的URL,不包含#及其后面部分)。例如:
- noncestr=Zn4zmLFKD0wzilzM
- jsapi_ticket=mS5k98fdkdgDKxkXGEs8LORVREiweeWETE40P37wkidkfksDSKDJFD5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcKIDU8l
- timestamp=1414588745
- url=http://open.dingtalk.com
步骤1. sort()含义为对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)
步骤2. assemble()含义为根据步骤1中获的参数字段的顺序,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串
步骤2. sha1()的含义为对在步骤2拼接好的字符串进行sha1加密。(PS:明明是步骤3好么!)
一开始没有理解,用代码生成签名和官方的就是对不上,很是打击。但是后来发现就是没有理解文档中的第一步,后来发现是:签名参数按照【字段名】而非一开始理解的参数值。
既然理解了,那么先看看签名参数按照字段名noncestr、jsapi_ticket、timestamp和url的字典排序吧:
ArrayList AL = new ArrayList();
AL.Add("noncestr");
AL.Add("jsapi_ticket");
AL.Add("timestamp");
AL.Add("url");
AL.Sort();
那么下一步就是拼接字符串了:
string assemble =string.Format("jsapi_ticket={0}&noncestr={1}×tamp={2}&url={3}", jsapi_ticket, noncestr,sTimeStamp, url);
最后一步骤:
sha = new SHA1CryptoServiceProvider();
enc = new ASCIIEncoding();
byte[] dataToHash = enc.GetBytes(assemble);
byte[] dataHashed = sha.ComputeHash(dataToHash);
hash = BitConverter.ToString(dataHashed).Replace("-", "");
hash = hash.ToLower();
完整代码如下,注意此包含时间戳的生产方法:
using System;
using System.Text;
using System.Security.Cryptography;
using Suite.Corp;
using System.Collections;
/*
* Author:JackWangCUMT
* Date:2016-04-26 8:36
* Blogs:http://www.cnblogs.com/isaboy
* GitHub:https://github.com/JackWangCUMT
* QQ:308106637
*/
namespace myDDDev
{
public static class DingTalkAuth
{
/// <summary>
///开发者在web页面使用钉钉容器提供的jsapi时,需要验证调用权限,并以参数signature标识合法性
///签名生成的规则:
///List keyArray = sort(noncestr, timestamp, jsapi_ticket, url);
/// String str = assemble(keyArray);
///signature = sha1(str);
/// </summary>
/// <param name="noncestr">随机字符串,自己随便填写即可</param>
/// <param name="sTimeStamp">当前时间戳,具体值为当前时间到1970年1月1号的秒数</param>
/// <param name="jsapi_ticket">获取的jsapi_ticket</param>
/// <param name="url">当前网页的URL,不包含#及其后面部分</param>
/// <param name="signature">生成的签名</param>
/// <returns>0 成功,2 失败</returns>
public static int GenSigurate(string noncestr, string sTimeStamp, string jsapi_ticket, string url, ref string signature)
{ //例如:
//noncestr = Zn4zmLFKD0wzilzM
//jsapi_ticket = mS5k98fdkdgDKxkXGEs8LORVREiweeWETE40P37wkidkfksDSKDJFD5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcKIDU8l
//timestamp = 1414588745
//url = http://open.dingtalk.com //步骤1.sort()含义为对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)
//注意,此处是是按照【字段名】的ASCII字典序,而不是参数值的字典序(这个细节折磨我很久了)
//0:jsapi_ticket 1:noncestr 2:timestamp 3:url; //步骤2.assemble()含义为根据步骤1中获的参数字段的顺序,使用URL键值对的格式(即key1 = value1 & key2 = value2…)拼接成字符串
//string assemble = "jsapi_ticket=3fOo5UfWhmvRKnRGMmm6cWwmIxDMCnniyVYL2fqcz1I4GNU4054IOlif0dZjDaXUScEjoOnJWOVrdwTCkYrwSl&noncestr=CUMT1987wlrrlw×tamp=1461565921&url=https://jackwangcumt.github.io/home.html";
string assemble =string.Format("jsapi_ticket={0}&noncestr={1}×tamp={2}&url={3}", jsapi_ticket, noncestr,sTimeStamp, url);
//步骤2.sha1()的含义为对在步骤2拼接好的字符串进行sha1加密。
SHA1 sha;
ASCIIEncoding enc;
string hash = "";
try
{
sha = new SHA1CryptoServiceProvider();
enc = new ASCIIEncoding();
byte[] dataToHash = enc.GetBytes(assemble);
byte[] dataHashed = sha.ComputeHash(dataToHash);
hash = BitConverter.ToString(dataHashed).Replace("-", "");
hash = hash.ToLower();
}
catch (Exception)
{
return ;
}
signature = hash;
return ; } /// <summary>
/// 获取时间戳timestamp(当前时间戳,具体值为当前时间到1970年1月1号的秒数)
/// </summary>
/// <returns></returns>
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(, , , , , , );
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
/// <summary>
/// 字典排序
/// </summary>
public class DictionarySort : System.Collections.IComparer
{
public int Compare(object oLeft, object oRight)
{
string sLeft = oLeft as string;
string sRight = oRight as string;
int iLeftLength = sLeft.Length;
int iRightLength = sRight.Length;
int index = ;
while (index < iLeftLength && index < iRightLength)
{
if (sLeft[index] < sRight[index])
return -;
else if (sLeft[index] > sRight[index])
return ;
else
index++;
}
return iLeftLength - iRightLength; }
}
}
}
代码已经放置在GitHub上:https://github.com/JackWangCUMT/DDHelper
钉钉客户端JS-API权限签名算法.NET版的更多相关文章
- js api 实现钉钉免登
js api 实现钉钉免登,用于从钉钉微应用跳转到企业内部的oa,erp等,我刚刚实施完了我公司的这个功能,钉钉用起来还不错. 1 js api 实现钉钉免登,页面配置. <title>利 ...
- 钉钉服务端api接口使用
原文链接:http://www.cnblogs.com/xiaosongJiang/p/9991573.html 第一步:注册钉钉企业账号 打开链接:https://oa.dingtalk.com/# ...
- 钉钉js依赖库学习
看别人用的依赖库的好处在于,你知道有什么可以用,什么可以借鉴.(钉钉——协作桌面应用) PS:人最怕是不知道,而不是你不会. 1. jQuery 钉钉使用了1.9.1版本的jQuery,jQuery作 ...
- 微信客户端自带的Js Api:WeixinJSBridge
<!DOCTYPE html> <html> <head> <title>微信WeixinJSBridge API</title> < ...
- 通过钉钉网页上的js学习xss打cookie
做完了一个项目,然后没啥事做,无意看到了一个钉钉的外部链接: 题外话1: 查看源码,复制其中的代码: try { var search = location.search; if (search &a ...
- 这个API Hub厉害了,收录了钉钉企业微信等开放Api,还能直接调试
01 此前时不时会有一些研发小伙伴和我诉苦,说很多企业由于人力财力限制或者需求不强,会直接购买使用第三方的开放API,这样一来, 一则由于开放项目不是量身定制的,寻找自己合适的接口也要搜索调研蛮多时间 ...
- ASP.NET C# 实现钉钉签名算法
在 https://open-doc.dingtalk.com/microapp/faquestions/hxs5v9 钉钉给出了JAVA/PHP算法,下面是C#算法 using System.Sec ...
- 钉钉如何进行PC端开发
前段时间,用钉钉进行了服务器端的开发,对照着官方文档,感觉还是比较顺利的.后续想有时间研究一下PC端客户端的开发,看着官方文档,说的确实是比较简练,但也确实没看太明白,废了半天劲也没成功.后来经过无数 ...
- Java钉钉开发_02_免登授权(身份验证)(附源码)
源码已上传GitHub: https://github.com/shirayner/DingTalk_Demo 一.本节要点 1.免登授权的流程 (1)签名校验 (2)获取code,并传到后台 (3) ...
随机推荐
- CGContextTranslateCTM: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
最近在测试的过程中, 发现了SpringBoar的一个问题: SpringBoard[53] <Error>: CGContextTranslateCTM: invalid context ...
- web开发者谷歌浏览器常用插件
1.Allow-Control-Allow-Origin 安装此插件解决跨域问题,在本地起服务器可访别的域的数据. 需在Access-Control-Expose-Headers加上Allow- ...
- Android中include标签的使用
在Android的开发中,我们知道布局文件可以让我们很方便的对各个UI控件进行位置安排跟属性设置,而在程序中可以直接取得控件并赋予对应操作功能.但是,如果是一个复杂的界面设计,我们把所有布局都放在一个 ...
- 麒麟系统使用root权限运行程序
最近在虚拟机里安装了个国产麒麟系统.(不知道麒麟系统的百度下.) ************************************************** 官方网址:http://www. ...
- 把图片加载到BufferedImage中
把图片加载到BufferedImage 中有什么作用呢?它就可以利用 ImageIO.write(image, "JPEG", response.getOutputStream() ...
- React-Native 给客户端来个「同音词模糊搜索」
APP上线一段时间有用户反应说不方便找东西,其实APP的数据不大也就三四百条而以,但受限于手机端展示区域太小.信息大爆炸,大家也基本上不会去记具体的名称都是根据模糊的印象进行搜索而且现在大家基本都用拼 ...
- SQL--联合查询【Union】
集合运算符是针对两个集合操作的,两个集合必须有相同的列数:列具有相同的数据类型(至少能够隐式转换的);最终输出的集合的列名是,由第一个集合的列名来确定的(可以用来连接多个结果). 注意:联合[Unio ...
- C# 代码编程规范
1. 类一定要有注释 2. C#代码要用#region包起来,#region之间要留一个且只留一个空行 3. 含义复杂不容易看懂的参数要写注释 4. 方 ...
- WPF系列:无边框窗口
<Window x:Class="Ares.Animations.Window3" xmlns="http://schemas.microsoft.com/winf ...
- jquery.tmpl.js 模板引擎用法
1.0 引入: <script src="/js/jquery.tmpl.min.js"></script> 2.0 模板: <script type ...