如何写一个微信小游戏的后台
昨天在公众号,分享了一个H5小游戏,这个项目虽然简单,但是我觉得细节比较多,对于新手来说是一个不错的锻炼,麻雀虽小,五脏俱全。涉及到了一些初级的鉴权、缓存、并发、安全,所以我今天特地写了篇小结,一是积累经验,二是交流分享。如有错误,还请指正。
由于这篇文章引用了其他一些文章,但是公众号推文无法直接跳转外链,所以可以点击文末的“查看原文”进入我的博客,再从博客内跳转到引用文章。引用的这两篇,质量都挺高的,值得一读。
下面我就从几个方面来谈总结一下这次的中秋活动的后台,未体验过的,可以点击这篇文章:中秋快乐,体验一个H5小游戏。
微信公众平台鉴权
用户在微信客户端中打开第三方网页时,微信公众平台可以提供相关的用户信息,以方便第三方的业务使用。
但是在此之前需要通过公众平台的鉴权,鉴权方式基于OAuth2.0的授权码模式。(什么是OAuth2.0?)
作为客户端,我们需要提供一个REDIRECT_URI去让微信的权限验证服务器回调。在用户确认授权后,将会返回一个code
,使用这个code
,我们能够获取access_token
和用户的openid
,使用这些参数再去请求微信资源服务器中的用户个人信息。
微信JS SDK
微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。
所有需要使用JS-SDK的页面必须先注入配置信息。
主要包含以下几个参数:
- appId
- timestamp
- nonceStr
- signature(包含url信息和jsapi_ticket信息,使用SHA1签名)
游戏得分的加密
这个游戏中,得分是一个比较关键的存在,因为直接关系到礼品,而且如果不做加密措施,在传输中被别人随意修改,也比较难看。
- 传输过程中被篡改
HTTP明文协议的缺陷,是导致数据泄露、数据篡改、流量劫持、钓鱼攻击等安全问题的重要原因。HTTP协议无法加密数据,所有通信数据都在网络中明文“裸奔”。通过网络的嗅探设备及一些技术手段,就可还原HTTP报文内容。
所以现在一般都会上https
(什么是https?),使用了https后,基本消除了中间人问题。
- 用户完全不需要在传输过程中篡改啊,直接自己在源头发一个请求,伪造一个高分的参数
对于这个问题,如果前端用对称加密,用js对游戏得分加密一下,但是这段js是裸露的,好像没什么用。
前端在需要将分数信息post到后端之前,请求一个api,api实现了将openid与一个随机数缓存到后端,然后将
data = base64(
1 | { |
)
post到后端,后端取到值,取出k,与后台缓存中的信息进行比对,一致的话才认为当前分数为有效分数。
通过服务端生成的随机参数,每次请求携带这个参数,攻击者他是无法知道这个随机值是什么的,所以伪造的请求也就无法通过校验。
实时排行榜
做这个排行榜时,我当时的想法是将用户得分保存在Mysql中,然后定时执行一次排序,将前50名的信息缓存,然后所有用户查看这个排行榜的话,都是从缓存中获取数据。
但是产品的要求是不能接受延迟,需要实时刷新,这就产生了问题,因为关系型数据库的执行效率有限,请求一次排序一次肯定是不可能的,所以准备通过缓存来维护,正好可以使用redis的zset这个数据结构。
但是zadd的时间复杂度为O(M*log(N)),假如集合过大,排序对性能影响很大,所以觉得没有必要维护所有玩家的得分,只需要TOP100(具体前端需要n位自己从里面取)的数据就够了。
在维护实时排行榜时,对redis有多次操作,要注意事务的问题。
所以最后是这样,维护三类key:
- rank. + openid,string类型,key = openid , value = 最新的rankresponse
- userScore,zset类型 , score = score, member = openid
- lowRank,string类型, TOP100中score最低的一位,每次有玩家分数进来,先与lowRank比较
Pingback统计
在每个页面及按钮上设置埋点,用于统计按钮点击总数和页面显示总数,这个并发量应该是很高的,关系型数据库的读写能力可能有限,所以还是使用redis,注意原子操作。
为了便于活动之后的数据分析,这里我使用分时+分域的方式,粒度为每小时,便于之后产品的总结工作。
整个流程:
请求微信权限验证->获取code->获取access_token->获取userInfo->持久化用户信息到Mysql->将openid加入cookie->将index_url加入headers-Location返回->用户被重定向到首页,开始游戏->后台生成随机值->记录pingback->携带随机值与的得分请求后台->维护排行榜。