微信小程序登录那些事

51次阅读

共计 3311 个字符,预计需要花费 9 分钟才能阅读完成。

最近团队在开发一款小程序,都是新手,一边看文档,一边开发。在开发中会遇到各种问题,今天把小程序登录这块的流程整理下,做个记录。
小程序的登录跟平时自己 APP 这种登录验证还不太一样,多了一个角色,那就是微信服务器。

根据微信官方提供的登录流程时序图可以清楚的了解小程序登录需要多少个步骤,下面我们来总结下:

小程序启动,通过 wx.login() 获取 code
开发者服务器需要提供一个登录的接口,参数就是小程序获取的 code
登录接口收到 code 后,调用微信提供的接口进行 code 的验证
得到验证结果,成功后能得到一个 session_key 和 openid
生成一个自定义的 key, 将 session_key 和 openid 跟自定义的 key 关联起来
将自定义的 key 返回给小程序
每次请求都带上 key, 后端根据 key 获取 openid 识别当前用户身份

首先 code 是微信给的,如果你随意生成 code 去验证肯定是无效的,只有微信给的 code 才有效。code 传到开发者自己的服务后,再去问微信:
Hi 哥们,我这个 code 是有效的还是无效的啊?
微信会告诉你是有效还是无效,有效的情况下还会给你一个用户的标识,也就是 openid,同时还会有一个 session_key,也就是会话的 key。session_key 的有效期默认是 2 小时,当用户一直在使用小程序的话会自动刷新,这个是由微信这边来维护的。
注意:

会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
临时登录凭证 code 只能使用一次

所以我们要为 session_key 创建别名,这个别名关联的哪个用户只有我们自己知道,唯一需要做的工作就在这块。
我推荐 2 种方式来做关联:
第一种:随机生成 key, 关联 openid,存入 redis 中,当请求带入 key,直接从 redis 中获取 openid 得到当前用户信息,这个其实也就是我们自己去维护了会话信息
第二种:采用 JWT 生成 token,将 openid 绑定到 token 中,将 token 返回给小程序,请求的时候带上 token,通过解析 token 得到用户信息。
下面我们以第二种方式来进行讲解,会贴上部分代码:
小程序中在 app.js 中的 onLaunch 方法中增加获取 code 方法,并且调用后端的登录接口获取 token:
wx.login({
success: function (res) {
var code = res.code;
if (code) {
console.log(‘app 启动获取用户登录凭证:’ + code);
let params = {“code”: code};
let result = config.requestHttp(config.url.userLogin, ‘POST’, params)
result.then(res => {
let data = res.data
if (data.code == 200) {
wx.setStorageSync(“login_token”, data.data.token);
}
}).catch(err => {
console.log(err)
});
} else {
console.log(‘ 获取用户登录态失败:’ + res.errMsg);
}
}
})
userLogin 接口则根据小程序的 code 去调用微信接口验证:
// 小程序获取 SessionKey 接口地址
String loginUrl = “https://api.weixin.qq.com/sns/jscode2session”;
String url = loginUrl + “?appid=%s&secret=%s&grant_type=%s&js_code=%s”;
url = String.format(url, appid, appSecret, grantType, param.getCode());
String result = restTemplate.getForObject(url, String.class);
Map<String, Object> map = JsonUtils.toBean(Map.class, result);
// 请求成功
if (map.containsKey(“session_key”)) {
String openid = map.get(“openid”).toString();
// 第一次保存到用户表,生成 JWT TOKEN 返回
}
小程序端需要将 wx.request() 封装成一个通用的方法,所有跟后台交互都用这个方法来调用接口,我们可以在这个方法中设置登录之后获取的 Token。这样每次请求都会将 Token 塞到请求头中,我们在网关中就可以获取这个 Token 进行解析验证。
// 请求封装
function requestHttp(url, method, data) {
// 请求头设置
var header = {
Authorization: wx.getStorageSync(“login_token”)
}
return new Promise((resolve, reject) => {
wx.request({
url: config.home_config + url,
data: data,
header: header,
method: method,
success: (res => {
if (res.data.code === 200) {
resolve(res)
} else {
reject(res)
}
}),
fail: (res => {
reject(res)
})
})
})
}
Zuul 中进行验证:
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String token = request.getHeader(“Authorization”);
if (StringUtils.isBlank(token)) {
ctx.setSendZuulResponse(false);
ctx.set(“isSuccess”, false);
ctx.setResponseBody(JsonUtils.toJson(Response.fail(“ 非法请求【缺少 Authorization】”, ResponseCode.NO_AUTH_CODE)));
ctx.getResponse().setContentType(“application/json; charset=utf-8”);
return null;
}

// 验证 Token 是否有效
JWTResult jwResult = JWTUtils.checkToken(token);
if (!jwResult.isStatus()) {
ctx.setSendZuulResponse(false);
ctx.set(“isSuccess”, false);
ctx.setResponseBody(JsonUtils.toJson(Response.fail(jwResult.getMsg(), jwResult.getCode())));
ctx.getResponse().setContentType(“application/json; charset=utf-8”);
return null;
}
ctx.addZuulRequestHeader(“loginUserId”, jwResult.getUid());
return null;
验证成功后将用户 ID 设置到请求头中,传递给后端服务使用。
使用 JWT 必然有一个问题是 Token 的失效问题,我这边失效时间设置的为 2 个小时,正常的话用户打开小程序,使用不可能连续超过 2 个小时,登录的逻辑是在 app.js 中做的,只要下次进去 token 就会重新申请。不过这个也可以调整,比如稍微长一点。
核心就是用户的认证交给了微信,只要微信告诉我们认证成功了,我们就可以自己接管会话信息了。
欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

正文完
 0