前段时间写了一篇博文《钉钉如何进行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}&timestamp={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&timestamp=1461565921&url=https://jackwangcumt.github.io/home.html";
string assemble =string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={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版的更多相关文章

  1. js api 实现钉钉免登

    js api 实现钉钉免登,用于从钉钉微应用跳转到企业内部的oa,erp等,我刚刚实施完了我公司的这个功能,钉钉用起来还不错. 1 js api 实现钉钉免登,页面配置. <title>利 ...

  2. 钉钉服务端api接口使用

    原文链接:http://www.cnblogs.com/xiaosongJiang/p/9991573.html 第一步:注册钉钉企业账号 打开链接:https://oa.dingtalk.com/# ...

  3. 钉钉js依赖库学习

    看别人用的依赖库的好处在于,你知道有什么可以用,什么可以借鉴.(钉钉——协作桌面应用) PS:人最怕是不知道,而不是你不会. 1. jQuery 钉钉使用了1.9.1版本的jQuery,jQuery作 ...

  4. 微信客户端自带的Js Api:WeixinJSBridge

    <!DOCTYPE html> <html> <head> <title>微信WeixinJSBridge API</title> < ...

  5. 通过钉钉网页上的js学习xss打cookie

    做完了一个项目,然后没啥事做,无意看到了一个钉钉的外部链接: 题外话1: 查看源码,复制其中的代码: try { var search = location.search; if (search &a ...

  6. 这个API Hub厉害了,收录了钉钉企业微信等开放Api,还能直接调试

    01 此前时不时会有一些研发小伙伴和我诉苦,说很多企业由于人力财力限制或者需求不强,会直接购买使用第三方的开放API,这样一来, 一则由于开放项目不是量身定制的,寻找自己合适的接口也要搜索调研蛮多时间 ...

  7. ASP.NET C# 实现钉钉签名算法

    在 https://open-doc.dingtalk.com/microapp/faquestions/hxs5v9 钉钉给出了JAVA/PHP算法,下面是C#算法 using System.Sec ...

  8. 钉钉如何进行PC端开发

    前段时间,用钉钉进行了服务器端的开发,对照着官方文档,感觉还是比较顺利的.后续想有时间研究一下PC端客户端的开发,看着官方文档,说的确实是比较简练,但也确实没看太明白,废了半天劲也没成功.后来经过无数 ...

  9. Java钉钉开发_02_免登授权(身份验证)(附源码)

    源码已上传GitHub: https://github.com/shirayner/DingTalk_Demo 一.本节要点 1.免登授权的流程 (1)签名校验 (2)获取code,并传到后台 (3) ...

随机推荐

  1. SSIS的DelayValidation属性

    一,DelayValidation Property true if validation of the package is delayed until run time. false if the ...

  2. SQL Server的Execute As与连接池结合使用的测试

    简介     在SQL Server中,Execute As关键字允许当前账户在特定上下文中以另一个用户或登录名的身份执行SQL语句,比如用户张三有权限访问订单表,用户李四并没有权限访问订单表,那么给 ...

  3. PHP内核的学习--PHP生命周期

    一切的开始: SAPI接口 SAPI(Server Application Programming Interface)指的是PHP具体应用的编程接口, 就像PC一样,无论安装哪些操作系统,只要满足了 ...

  4. 机器学习&数据挖掘笔记_12(对Conjugate Gradient 优化的简单理解)

    数学优化方法在机器学习算法中至关重要,本篇博客主要来简单介绍下Conjugate Gradient(共轭梯度法,以下简称CG)算法,内容是参考的文献为:An Introduction to the C ...

  5. Azure ARM (4) 开始创建ARM Resource Group并创建存储账户

    <Windows Azure Platform 系列文章目录> 好了,接下来我们开始创建Azure Resource Group. 1.我们先登录Azure New Portal,地址是: ...

  6. Spark程序使用groupByKey后数据存入HBase出现重复的现象

    最近在一个项目中做数据的分类存储,在spark中使用groupByKey后存入HBase,发现数据出现双份( 所有记录的 rowKey 是随机  唯一的 ) .经过不断的测试,发现是spark的运行参 ...

  7. linux service命令解析

      我们平时都会用service xxx start来启动某个进程,那么它背后究竟执行了什么? 其实service的绝对路径为/sbin/service ,打开这个文件cat /sbin/servic ...

  8. QWebView在 Qt 5.x中编译出错:File not found: main.obj

    错误现象 近日由于项目需要,想要学习一下QWebView的使用.于是简单的建立了一个Qt工程,并编写了如下代码: #include <QApplication> #include < ...

  9. Entity Framework基础01

    学习了ADO.NET的相关知识,掌握了它对数据库表的基本操作,但是实际在开发项目应用中微软为我们开发ef这个ORM,使用它可以很方便的利用ADO.NET来操作DBMS,使得我们开发项目的着重点放在业务 ...

  10. C语言学习011:带参数的main函数

    直接上代码 #include <stdio.h> int main(int argc,char *argv[]){ printf("%i \n",argc); int ...