V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
sailxjx
V2EX  ›  问与答

求大神解答,微信 JS SDK 签名的服务端验证是怎么实现的

  •  
  •   sailxjx · 2015-09-18 18:23:55 +08:00 · 3981 次点击
    这是一个创建于 3372 天前的主题,其中的信息可能已经有所发展或是发生改变。

    根据文档流程 https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E6.AD.A5.E9.AA.A4.E4.B8.89.EF.BC.9A.E9.80.9A.E8.BF.87config.E6.8E.A5.E5.8F.A3.E6.B3.A8.E5.85.A5.E6.9D.83.E9.99.90.E9.AA.8C.E8.AF.81.E9.85.8D.E7.BD.AE jsticket 是由 api 生成的,而且每次刷新都不一样,到验证时, ws.config 中只提供了 appId,timestamp,nonceStr,signature 这些字段。

    wx.config ({
        debug: true, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。
        appId: '', // 必填,公众号的唯一标识
        timestamp: , // 必填,生成签名的时间戳
        nonceStr: '', // 必填,生成签名的随机串
        signature: '',// 必填,签名,见附录 1
        jsApiList: [] // 必填,需要使用的 JS 接口列表,所有 JS 接口列表见附录 2
    });
    

    那么,在微信的后台是如何将 signature 或 appId 和 jsticket 对应起来实现验证的,难道保存了所有 appId 对应的 jsticket 然后循环来匹配吗?

    13 条回复    2015-09-19 18:16:52 +08:00
    abelyao
        1
    abelyao  
       2015-09-18 18:51:44 +08:00
    上亿的 QQ 数据都可以保存,保存这点信息算啥… 何况还是有过期时间的……
    abelyao
        2
    abelyao  
       2015-09-18 18:54:02 +08:00
    另外他们也不需要循环匹配,原理都一样,你生成一个签名,他们也按照你的 timestamp 等信息去生成一个签名,看看是否匹配就行了。重点在于参与签名生成的某些函数不包含在数据包中,那样就算中间人抓包也无法伪造签名。
    abelyao
        3
    abelyao  
       2015-09-18 18:54:20 +08:00
    上面说错了,“某县函数” 应改为 “某些字段”
    qiayue
        4
    qiayue  
       2015-09-18 18:57:13 +08:00
    有 AppID ,直接找到你的 ticket ,同样的计算方式计算一遍
    sailxjx
        5
    sailxjx  
    OP
       2015-09-19 12:05:42 +08:00
    @qiayue 但是一个 AppID 会生成多个 ticket 啊
    sailxjx
        6
    sailxjx  
    OP
       2015-09-19 12:06:24 +08:00
    @abelyao 生成签名需要先找到对应的 ticket ,这个 ticket 可找不到一对一的关系
    abelyao
        7
    abelyao  
       2015-09-19 12:14:45 +08:00 via iPhone
    @sailxjx 那 ticket 会不会跟 access token 一样,重复获取覆盖上一个,也就意味着同时只有一个有效呢?
    qiayue
        8
    qiayue  
       2015-09-19 12:16:40 +08:00
    同一时间只有一个 ticket 生效,有效期 7200 秒,所以微信要求我们缓存 ticket 并且快要过期时去刷新获取新的 ticket
    建议楼主好好读一读微信开发者文档
    qiayue
        9
    qiayue  
       2015-09-19 12:18:14 +08:00
    jsapi_ticket

    生成签名之前必须先了解一下 jsapi_ticket , jsapi_ticket 是公众号用于调用微信 JS 接口的临时票据。正常情况下, jsapi_ticket 的有效期为 7200 秒,通过 access_token 来获取。由于获取 jsapi_ticket 的 api 调用次数非常有限,频繁刷新 jsapi_ticket 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存 jsapi_ticket 。

    参考以下文档获取 access_token (有效期 7200 秒,开发者必须在自己的服务全局缓存 access_token ):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
    用第一步拿到的 access_token 采用 http GET 方式请求获得 jsapi_ticket (有效期 7200 秒,开发者必须在自己的服务全局缓存 jsapi_ticket ): https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
    sailxjx
        10
    sailxjx  
    OP
       2015-09-19 13:38:54 +08:00
    @qiayue 文档并没有提到同一时间只有一个 ticket 有效,这样做也是不对的,因为同一时间会有不同的用户访问这个页面,使用不同的 ticket ,但是对应的 appid 是唯一的。
    sailxjx
        11
    sailxjx  
    OP
       2015-09-19 13:41:19 +08:00
    @qiayue 也可能是我理解错了,如果 7200 秒内只能有一个 ticket 生效,那么开发者就需要给所有访问用户使用同一个签名。
    我会测试一下微信接口是否一个应用只支持一个 ticket
    qiayue
        12
    qiayue  
       2015-09-19 14:22:31 +08:00
    不是说微信不给你生成 ticket ,而是你每次想要去生成,微信都会给你生成,但是生成一个新的 ticket 后,之前生成的就不起作用了(不知道微信是否会为了过渡顺利同时保留最后生成的两个 ticket )

    你可以试一下,每隔 1 秒钟生成 1 个 ticket ,然后生成 10 个 ticket 保存起来,分别用这 10 个 ticket 去计算得到签名,看看是否 10 个都能够分享成功(打开 debug 可以得到错误信息)

    另外,即使生成的每一个 ticket 都有效,但是一天的生成次数是有限的,假设如果是 1 万次的话,假设你的页面每一秒都有人访问并分享,那么一天 86400 次就会超过 1 万次的限制,所以流量小的时候,你每次都生成新的 ticket 是没问题的,流量大就不行。

    所以必须要缓存。
    abelyao
        13
    abelyao  
       2015-09-19 18:16:52 +08:00
    @sailxjx 看到你在 10 楼和 11 楼的回复便明白你是没有好好理解文档了,文档中已经非常强调自己缓存 ticket 意味着你这边不管是 1 个用户还是 1000 个用户在一定时间内都是使用缓存下来的这个。

    且不说微信有没有压力去应付你不同 ticket 的请求,你不觉得如果几万用户每次都去微信那边拿一下 ticket ,你的服务器也要承担这部分流量和耗时吗?而如果有换成的话,明显要快太多倍了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   863 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 22:14 · PVG 06:14 · LAX 14:14 · JFK 17:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.