内容主要包括微信公众号开发过程的简述,还有对相应的流程设计的思考。
申请账号
申请公众号,从公众号平台官网获取 appId、appSecret 等信息,同时可以配置 ip 白名单和 服务器配置项等信息
微信服务器向个人服务器推送信息
公众号用户的行为信息可以通过微信服务器推送到个人服务器,例如在公众号发送的 im 消息,支付等。微信服务器会产生相应的信息推送到个人服务器。
服务器的配置项中包括:URL、Token、EncodingAESKey、消息加解密方式。其中 Token 做为微信服务端凭证发送到个人服务器,为了防止 token 被猜出的情况下,个人服务器 api 被盗用的情况,可使用 EncodingAESKey 对消息进行对称加密,同时微信提供了用于获取自身服务 ip 列表的接口,个人服务端可以此验证请求来源。
个人服务器请求微信服务端
在获取用户 openID、access_token 和生成签名的过程中, 个人服务器需要向服务器发起请求。个人服务器通过提交 appId, appSecret 从微信服务器获取 access_token 做为通信时的身份凭证,access_token 需要定时刷新。
消息加密
个人服务器和微信客户端通信过程中可以选择加密方式,避免在不安全的网络中通信数据被窃取。加解密套件参数 token, encodingAesKey 在微信公众号后台配置,通信过程采用对称加密。
wxCrypt = new WXBizMsgCrypt(token, encodingAesKey, appId);
// 解密收到的密文
recMsg = wxCrypt.decryptMsg(msgSignature, timeStamp, nonce, encrypt_msg);
// 加密发送的消息
sendMsg = wxCrypt.encryptMsg(replayMsg, timeStamp, nonce);
// 其中 nonce 是随机数,msgSignature 为参数字典序拼接后 hash处理的结果
微信网页开发
授权过程
1、微信网页通过 OAuth2.0 方式鉴权
2、微信用户账号在一个开放平台主体下的每个应用会对应一个 openId,用于替代真实的用户账号保护隐私。同一个用户在一个主体的多个应用,其多个 openId 对应到唯一的 unionID,用于多个应用间的数据互通。
3、网页授权流程
- 引导用户进入授权页面同意授权,获取 code,带参数重定向回原页面,将 code 提交到个人服务器
用户授权作用域包括 snsapi_base 和 snsapi_userinfo,两者都可以获取到 code。snsapi_userinfo 则需要用户手动授权以获取到用户信息。
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
- 个人服务器通过 code、appId、appSecret 换取网页授权 access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
// 响应得到 openid 和 access_token
{
"access_token": "ACCESS_TOKEN",
"expires_in": 7200,
"refresh_token": "REFRESH_TOKEN",
"openid": "OPENID",
"scope": "SCOPE"
}
- 个人服务器通过 openid 确定用户身份(可以转换为 UnionID),并下发 access_token 到客户端,做为客户端的临时身份标志
由于 code 和 access_token 在一定时间内失效,获取 code 需要用户在微信客户端授权,用户 openId、unionId 没有发送到通信链路的需要,中间人不能伪造用户身份,可以保证用户登录过程的安全。
该 OAuth2.0 鉴权过程(跳转到授权页)和传统网页端的 OAuth2.0 认证过程不同在于没有输入账号密码的流程, 猜测在授权页 Js 可以从客户端获取到标志用户身份的某种凭证,进而生成用于验证身份的 code。
JS-SDK
微信客户端通过 JS-SDK 为 Javascript 提供了原生能力和丰富的功能。
开发过程
- 绑定域名
- 引入 JS 脚本
- 通过 config 配置参数
- 在 error 回调中处理错误
- 在 ready 接口回调中使用 js-sdk 功能
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
js-sdk 方法调用采用回调的方式,功能接口调用依赖于 wx.ready 事件的触发,相应的逻辑不好拆分,可以将接口封装到 Promise 对象。
window.$wxReadyPrm = new Promise((resolve, reject) => {
wx.error = reject
wx.ready = resolve
wx.config({...})
});
配置项中 绑定域名 避免 appId 相关的配置被其它域名下的网页盗用。
config 方法传入 jsApiList 用于在初始化过程检查接口权限,将运行时可能出现的问题前置,方便开发者提前判断。
signature 要求使用当前网页完整 url 等参数进行签名,在 绑定域名配置中 js-sdk 的认证粒度是域名,而 signature 可以由个人服务器根据 url 做更细粒度的认证。比如在某个子域名或者包含某些参数的情况下不予生成签名。
signature 的生成在个人服务端进行,将参数按字典序排序, 同时拼接 url、jsapi_ticket hash 处理后返回。其中 jsapi_ticket 由个人服务端向微信服务器请求获取, 可以用于对个人服务端进行认证。例如假设页面中恶意的第三方脚本通过自己服务器生成 signature, 由于没有有效的 jsapi_ticket 导致验证失败。
总结
-
在鉴权和对称加密通信时所使用到的参数需要在开放平台后台配置且不会被包含在通信数据中,从而保证了个人服务器和微信服务器之间通信过程的安全。
-
用户身份认证过程由微信客户端和微信认证页生成临时凭证,用户的真实账号信息不会传递给个人服务器,保障了用户隐私,用户的平台凭证(openId,unionID)不会包含在通信数据中(取决于开发者), 从而保证了公众号应用的数据安全,用户身份不被伪造。
总的来说,在开发者不出现错误设计的情况下,微信网页和微信与个人服务器的数据和通信安全由微信客户端和微信开放平台保证,可以当作是安全的。