zoukankan      html  css  js  c++  java
  • 钉钉客户端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的字典排序吧:

    1 ArrayList AL = new ArrayList();
    2 AL.Add("noncestr");
    3 AL.Add("jsapi_ticket");
    4 AL.Add("timestamp");
    5 AL.Add("url");
    6 AL.Sort();

    那么下一步就是拼接字符串了:

    string assemble =string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr,sTimeStamp, url);

    最后一步骤:

    1  sha = new SHA1CryptoServiceProvider();
    2  enc = new ASCIIEncoding();
    3  byte[] dataToHash = enc.GetBytes(assemble);
    4 byte[] dataHashed = sha.ComputeHash(dataToHash);
    5 hash = BitConverter.ToString(dataHashed).Replace("-", "");
    6 hash = hash.ToLower();

    完整代码如下,注意此包含时间戳的生产方法:

      1 using System;
      2 using System.Text;
      3 using System.Security.Cryptography;
      4 using Suite.Corp;
      5 using System.Collections;
      6 /*
      7 * Author:JackWangCUMT
      8 * Date:2016-04-26 8:36
      9 * Blogs:http://www.cnblogs.com/isaboy
     10 * GitHub:https://github.com/JackWangCUMT
     11 * QQ:308106637
     12 */
     13 namespace myDDDev
     14 {
     15     public static class DingTalkAuth
     16     {
     17         /// <summary>
     18         ///开发者在web页面使用钉钉容器提供的jsapi时,需要验证调用权限,并以参数signature标识合法性
     19         ///签名生成的规则:
     20         ///List keyArray = sort(noncestr, timestamp, jsapi_ticket, url);
     21         /// String str = assemble(keyArray);
     22         ///signature = sha1(str);
     23         /// </summary>
     24         /// <param name="noncestr">随机字符串,自己随便填写即可</param>
     25         /// <param name="sTimeStamp">当前时间戳,具体值为当前时间到1970年1月1号的秒数</param>
     26         /// <param name="jsapi_ticket">获取的jsapi_ticket</param>
     27         /// <param name="url">当前网页的URL,不包含#及其后面部分</param>
     28         /// <param name="signature">生成的签名</param>
     29         /// <returns>0 成功,2 失败</returns>
     30         public static int GenSigurate(string noncestr, string sTimeStamp, string jsapi_ticket, string url, ref string signature)
     31         {
     32 
     33 
     34             //例如:
     35             //noncestr = Zn4zmLFKD0wzilzM
     36             //jsapi_ticket = mS5k98fdkdgDKxkXGEs8LORVREiweeWETE40P37wkidkfksDSKDJFD5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcKIDU8l
     37             //timestamp = 1414588745
     38             //url = http://open.dingtalk.com
     39 
     40             //步骤1.sort()含义为对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)
     41             //注意,此处是是按照【字段名】的ASCII字典序,而不是参数值的字典序(这个细节折磨我很久了)
     42             //0:jsapi_ticket 1:noncestr 2:timestamp 3:url;
     43 
     44             //步骤2.assemble()含义为根据步骤1中获的参数字段的顺序,使用URL键值对的格式(即key1 = value1 & key2 = value2…)拼接成字符串
     45             //string assemble = "jsapi_ticket=3fOo5UfWhmvRKnRGMmm6cWwmIxDMCnniyVYL2fqcz1I4GNU4054IOlif0dZjDaXUScEjoOnJWOVrdwTCkYrwSl&noncestr=CUMT1987wlrrlw&timestamp=1461565921&url=https://jackwangcumt.github.io/home.html";
     46             string assemble =string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr,sTimeStamp, url);
     47             //步骤2.sha1()的含义为对在步骤2拼接好的字符串进行sha1加密。
     48             SHA1 sha;
     49             ASCIIEncoding enc;
     50             string hash = "";
     51             try
     52             {
     53                 sha = new SHA1CryptoServiceProvider();
     54                 enc = new ASCIIEncoding();
     55                 byte[] dataToHash = enc.GetBytes(assemble);
     56                 byte[] dataHashed = sha.ComputeHash(dataToHash);
     57                 hash = BitConverter.ToString(dataHashed).Replace("-", "");
     58                 hash = hash.ToLower();
     59             }
     60             catch (Exception)
     61             {
     62                 return 2;
     63             }
     64             signature = hash;
     65             return 0;
     66            
     67         }
     68 
     69         /// <summary>
     70         /// 获取时间戳timestamp(当前时间戳,具体值为当前时间到1970年1月1号的秒数)
     71         /// </summary>
     72         /// <returns></returns>
     73         public static string GetTimeStamp()
     74         {
     75             TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
     76             return Convert.ToInt64(ts.TotalSeconds).ToString();
     77         }
     78         /// <summary>
     79         /// 字典排序
     80         /// </summary>
     81         public class DictionarySort : System.Collections.IComparer
     82         {
     83             public int Compare(object oLeft, object oRight)
     84             {
     85                 string sLeft = oLeft as string;
     86                 string sRight = oRight as string;
     87                 int iLeftLength = sLeft.Length;
     88                 int iRightLength = sRight.Length;
     89                 int index = 0;
     90                 while (index < iLeftLength && index < iRightLength)
     91                 {
     92                     if (sLeft[index] < sRight[index])
     93                         return -1;
     94                     else if (sLeft[index] > sRight[index])
     95                         return 1;
     96                     else
     97                         index++;
     98                 }
     99                 return iLeftLength - iRightLength;
    100 
    101             }
    102         }
    103     }
    104 }

     代码已经放置在GitHub上:https://github.com/JackWangCUMT/DDHelper

  • 相关阅读:
    Mvc3绑定下拉菜单
    M vc3+ExtJs 数据格式转换(泛型集合转换为Json类型)
    python代码小实践之dorm_lab_changeIP
    2013网易互联网暑假实习笔试&面试
    python代码小实践之split_csv
    python代码小实践之data_structure_and_algorithm
    位运算
    weibo_json
    unsinged and (signed)
    01背包模板 开心的小明
  • 原文地址:https://www.cnblogs.com/isaboy/p/dingtalk_dd_js_api_auth_sigurate.html
Copyright © 2011-2022 走看看