移动端——微信内登陆与认证
之前一直做PC端比较多,最近在做公司的微信公众号,涉及到一个问题,我们这个公众号是为特定的企业开放的,用于园区资产平台管理,所以涉及到一个用户登录认证的问题。
一、描述。
在微信的内部页面运行:当用户未关注公众号(或企业号),则自动引导到关注画面,关注后进入公众号,公众号中有“主页”,用户点击进入我们的平台,可以实现提交工单服务需求,查看园区信息等。但是在进入我们平台时需要做一个登录认证。
具体:如果用户尚未登录(未获取到其身份信息)时,则跳至特定页面获取凭证。已经登录则继续判断是否与我们平台进行了绑定,没有绑定则跳至绑定页面填写信息进行绑定,成功后方可进入平台。
二、实现。
由于平台开发文档发生了更新,所以流程变化如下:
最终流程:在平台内的任一页面,判断该 Url 中是否有 accessKey 参数存在,无则跳至指定 url 获取 accessKey,获取后自动跳至主页;有则跳转至主页,按照我们设置的流程进入我们的平台。在进入平台主页时判断用户是否与平台绑定,已绑定则存 accessKey ,没绑定则跳至绑定页面进行绑定。
【 即上图 3 中去掉了主页判断。】
所以,在公共js文件中:
1、判断有无凭证(accessKey)。
var accessKey = ""; var my_userId = ""; var my_userName = ""; // 内部认证参数 var APPID = ''; var REDIRECT_URI = encodeURIComponent("redirect_uri"); var SCOPE = 'snsapi_userinfo'; // 静默授权 var STATE = 'home'; // 认证后跳转的目标 var url_accessKey = getUrlParam('accesskey'); /*判断有无凭证*/ if(url_accessKey){ legal(); }else{ if (window.localStorage.getItem('accesskey')) { accessKey = window.localStorage.getItem('accesskey'); my_userId = window.localStorage.getItem('userId'); my_userName = window.localStorage.getItem('userName'); var saveTime = localStorage.getItem('saveTime'); var nowdate = (new Date()).getTime(); var a = nowdate - saveTime; a= (a/1000/60/60/24); if (a > 2) { // 过期时间2天,过期重新获取accessKey illegal(); // 无凭证或非法,跳到特定页面获取凭据 } }else{ //alert('url+local都无,无凭证,去获取'); illegal(); // 无凭证或非法,跳到特定页面获取凭据 } }
【 上述内部认证参数 APPID、REDIRECT_URI、SCOPE、STATE 在平台开发文档中有,这里的 APPID 和 REDIRECT_URI 就不写出来了。 】
但是,要注意的一个地方是,REDIRECT_URI 需要编码,不能直接写文档中的 http://.....
2、有无凭证情况下执行对应函数。
function illegal(){ var new_href = ('https://open.weixin.qq.com/connect/oauth2/authorize?appid='+APPID+'&redirect_uri='+REDIRECT_URI+ '&response_type=code&scope='+SCOPE+'&state='+STATE+'#wechat_redirect').toLowerCase(); window.location.href = new_href; } // 存accessKey function legal(){ var url_accessKey = getUrlParam('accesskey'); var url_userId = getUrlParam('userid'); var url_userName = getUrlParam('userName'); localStorage.setItem('accesskey', url_accessKey); // localStorage.setItem('userName', url_userName); // localStorage.setItem('userId', url_userId); // localStorage.setItem('saveTime', (new Date()).getTime());// 保存变量时的时间点,当前时间戳 my_userId = url_userId; my_userName = url_userName; accessKey = url_accessKey; }
3、获取 url 中的参数,getUrlParam():
//获取url中的参数 function getUrlParam(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象 var r = window.location.search.substr(1).match(reg); //匹配目标参数 // if (r != null) return unescape(r[2]); return null; //返回参数值 (解析中文参数时候出现乱码) if (r != null) return decodeURI(r[2]); return null; //返回参数值 }
比较无奈的是,获取 url 中的参数要改成下面的才行。
function getUrlParam(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象 var r = window.location.search.substr(1).match(reg); //匹配目标参数 // if (r != null) return unescape(r[2]); return null; //返回参数值 (解析中文参数时候出现乱码) if (r != null) {//返回参数值 return decodeURI(r[2]); }else{ return null; } }
三、调试。
在将代码上传到服务器上之后,需要进行很重要的一步,就是调试,测试可能出现的各种问题,我用的是微信web开发者工具,用起来还可以,就是感觉每次都要清除缓存有点麻烦。
1、在 WebStorm 中运行除主页的任一页面(服务详情页面),在浏览器中会出现提示:
2、能出现提示,至少说明跳去微信内部是对的,复制上面的链接在微信web开发者工具中打开:
由于我之前已经登录了,localStorage 中已经存在 accessKey ,所以正在自动登录。
3、但是我还没有绑定信息,所以会跳至信息绑定页面:
提交信息之后,绑定成功。
【 这里有个信息绑定是因为我们的公众号的使用人群是工程服务团队的,如果使用者不在工程服务团队中,是收不到验证码,也看不到任何信息的。即文章开始说的 为特定的企业开放。】
4、再次在微信web开发者工具中打开刚刚复制的链接:
这次是 之前登录过且已绑定信息 的状态。
5、点击主页中的各个模块进入对应的模块内容:
但是,我点模块进去,总是重复出现上面的 4 。查找原因,即 二、实现 中的流程3 ,不用做主页判断,做了主页判断,每次点都是只能进主页 o(╯□╰)o
四、手机获取验证码。
哈哈,今天来更新我之前遇到的问题,其实发了这篇之后就解决了,但是一直没时间写。之前遇到的奇怪问题是因为后台给的开发文档中的返回信息,大小写写错了,好无奈、、、
不过值得一提的是 Ajax 的跨域请求问题,这个我会在后面详细写一篇。
五、扩展 。
1、扫码方式绑定信息:
由于项目使用对象的扩展,目前这个微信公众号适用于多家企业,所以,我们使用扫码绑定信息从而确定用户绑定的项目。
用户扫码后公众号会推送绑定信息,点击进入绑定页面,扫描的二维码中包含用户所在项目及用户名、手机号,会自动填充至页面。
2、url 后面加参数:
在写获取 url 中的参数的函数时候,想到了,于是。。。
// 在url后面加参数 function UrlUpdateParams(url, name, value){ var r = url; if (r != null && r != 'undefined' && r != "") { value = encodeURIComponent(value); var reg = new RegExp("(^|)" + name + "=([^&]*)(|$)"); var tmp = name + "=" + value; if (url.match(reg) != null) { r = url.replace(eval(reg), tmp); } else { if (url.match("[\?]")) { r = url + "&" + tmp; } else { r = url + "?" + tmp; } } } return r; }