首页 > 代码库 > 钉钉开发笔记(4) 签名验证问题的处理

钉钉开发笔记(4) 签名验证问题的处理

忙了一天竟然在一个以前自认为,很基础的问题上卡顿了,为了防止以后出现类似错误,决定还是记录下来,顺便整理下思路!


 

钉钉开发中有PC和移动之分,这个已经讲过,其中最基础也是最重要的当属其中的签名验证了,也只有这个步骤成功了你才可以调取JSAPI文档中的一些组件的接口。(不用钉钉组件的童鞋可以无视我这句  -。-)

 

其中PC版的签名验证算法如图:

 1 JS-API权限签名算法 2  3 如果开发者想使用钉钉容器开放的jsapi接口,需要经过以下流程: 4  5 首先需要获取jsapi_ticket。 6 然后在web页面加载到钉钉容器时,通过jsapi权限验证配置接口验证可用的jsapi。这个接口使用的参数signature,在下文中有详细的说明。 7 1.获取jsapi_ticket 8  9 jsapi_ticket,是开发者调用钉钉JS接口的临时授权码,其作用主要用于生成签名,这个签名在jsapi权限验证配置接口中使用。10 11 正常的情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。12 13 获取jsapi_ticket,具体可以参考文档14 15 2.签名生成算法16 17 开发者在web页面使用钉钉容器提供的jsapi时,需要验证调用权限,并以参数signature标识合法性18 19 签名生成的规则:20 21 List keyArray = sort(noncestr,timestamp,jsapi_ticket,url);22 23 String str = assemble(keyArray);24 25 signature = sha1(str);26 27 参与签名的字段包括在上文中获取的jsapi_ticket,noncestr(随机字符串,自己随便填写即可),timestamp(当前时间戳,具体值为当前时间到1970年1月1号的秒数),url(当前网页的URL,不包含#及其后面部分)。例如:28 29 noncestr=Zn4zmLFKD0wzilzM30 jsapi_ticket=mS5k98fdkdgDKxkXGEs8LORVREiweeWETE40P37wkidkfksDSKDJFD5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcKIDU8l31 timestamp=141458874532 url=//open.dingtalk.com33 步骤1. sort()含义为对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)34 35 步骤2. assemble()含义为根据步骤1中获的参数字段的顺序,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串36 37 步骤2. sha1()的含义为对在步骤2拼接好的字符串进行sha1加密。

 

移动客户端签名验证如下:

 1 1.获取jsapi_ticket 2  3 jsapi_ticket,是开发者调用钉钉JS接口的临时授权码,其作用主要用于生成签名,这个签名在jsapi权限验证配置接口中使用。 4  5 正常的情况下,jsapi_ticket的有效期为7200秒,通过access_token(注意,假如您是ISV开发者,这个access_token需要企业授权的access_token接口)来获取。由于频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。 6 获取jsapi_ticket,具体可以参考文档) 7  8 2.签名生成算法 9 10 开发者在web页面使用钉钉容器提供的jsapi时,需要验证调用权限,并以参数signature标识合法性11 12 签名生成的规则:13 14 List keyArray = sort(noncestr,timestamp,jsapi_ticket,url);15 16 String str = assemble(keyArray);17 18 signature = sha1(str);19 20 参与签名的字段包括在上文中获取的jsapi_ticket,noncestr(随机字符串,自己随便填写即可),timestamp(当前时间戳,具体值为当前时间到1970年1月1号的秒数),url(当前网页的URL,不包含#及其后面部分,需要对url中query部分做一次urldecode)。例如:21 22 noncestr=Zn4zmLFKD0wzilzM23 jsapi_ticket=mS5k98fdkdgDKxkXGEs8LORVREiweeWETE40P37wkidkfksDSKDJFD5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcKIDU8l24 timestamp=141458874525 url=//open.dingtalk.com26 注意:必须要对生成签名的url的query部分做一次urldecode。例如,如果你的url是http://abc.com?url=http%3A%2F%2Fabc.com%2somewhere,那么你在生成签名的时候用到的url应该是对原url做过decode的url,即http://abc.com?url=http://abc.com/somewhere。否则可能会导致签名和服务端对应不上。27 28 步骤1. sort()含义为对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)29 30 步骤2. assemble()含义为根据步骤1中获的参数字段的顺序,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串31 32 步骤2. sha1()的含义为对在步骤2拼接好的字符串进行sha1加密。

 

 

其实仔细看来你就会发现,他们的唯一不同的地方就在于:移动端有url的编码,另外我可以告诉你,有没有编码的这一部分取决于你的url中是否存在中文字符,那么问题来了,是不是说移动和PC端的应用开发可以用同一套的签名呢?

答案是肯定的,而且是必须的!

 

为什么呢?

因为,在你获取accessToken的时候,你会发现他需要传入的参数只有corpId与CorpSecret,而且这两个入参是死值,也就是说,一个企业到的accessToken只有一个,而一个accessToken对应一个js_tiket,而且他们是存在时效和调取限制的yo!

 1 建立连接 2  3 更新时间:2016/07/15 访问次数:31492 4 主动调用 5 主动调用的频率限制 6 获取AccessToken 7 获取微应用后台管理免登SsoToken 8 你可以使用以下两种方式,将钉钉微应用连接到你的企业应用: 9 10 企业应用服务器调用钉钉开放平台提供的接口,以钉钉微应用的身份给企业用户的钉钉账号推送消息,以下称 主动调用模式。11 12 钉钉用户在使用企业提供的微应用H5页面时,该页面可以调用钉钉提供的JS接口,使用钉钉开放的终端能力和业务能力,以下称 JSAPI模式。13 14 钉钉服务器把用户发送的消息或用户触发的事件推送给企业应用,由企业应用处理,以下称 回调模式。15 16 主动调用17 18 当企业应用服务器调用钉钉开放平台接口时,需使用https协议、Json数据格式、UTF8编码,访问域名为 https://oapi.dingtalk.com。19 在每次主动调用钉钉开放平台接口时需要带上AccessToken参数。AccessToken参数由CorpID和CorpSecret换取。对于ISV来说,获取企业授权的access_token20 21 CorpID是企业在钉钉中的标识,每个企业拥有一个唯一的CorpID;22 23 CorpSecret是企业每个应用的凭证密钥。24 25 CorpID及CorpSecret可以在钉钉为企业提供的管理后台中找到,由钉钉自动分配。26 27 POST请求请在HTTP Header中设置 Content-Type:application/json,否则接口调用失败28 主动调用的频率限制29 30 当你获取到AccessToken时,你的微应用后台就可以成功调用钉钉后台所提供的各种接口或访问相应企业的资源或给成员发消息。31 32 为了防止微应用的程序错误而引发钉钉服务器负载异常,默认情况下,每个服务端调用接口都有一定的频率限制,当超过此限制时,调用对应接口会收到相应错误码。33 34 以下是当前默认的频率限制,钉钉后台可能会根据运营情况调整此阈值:35 36 每个企业调用单个接口的频率不可超过1500次/分37 38 每个ISV(应用提供商)调用单个接口的频率不可超过2000次/分39 40 每个ISV(应用提供商)调用单个企业的单个接口频率不可超过1500次/分41 42 每个套件调用单个企业的单个接口频率不可超过1000次/分43 44 获取AccessToken45 46 AccessToken是企业访问钉钉开放平台接口的全局唯一票据,调用接口时需携带AccessToken。47 48 AccessToken需要用CorpID和CorpSecret来换取,不同的CorpSecret会返回不同的AccessToken。正常情况下AccessToken有效期为7200秒,有效期内重复获取返回相同结果,并自动续期。

 

 

所以一般都会存在缓存策略,但是缓存策略的话会存在一个问题,那就是tiket的时效性问题!

 

即,一般公司存在多个项目时,大多会开发多个独立的数据库项目与之对应。往往会在其每个数据库中独自调用一种配置方法,但是这也是问题所在!所以我推荐大家采用多个项目调用一种配置的方法。这样就不会存在tiket时效从而签名验证失败的问题了!

 

钉钉开发笔记(4) 签名验证问题的处理