前言

本次演示采用nodejs(>7.5)+express+request框架,需要有一定的基础.层级分为四层分别为

  • 路由层
  • 控制层
  • 请求层
  • 视图层

路由层

  • GET /login # login登录页
  • GET /login/wechat # mobile微信跳转返回页
  • GET /login/wechat-pc # pc跳转返回页

控制层

  • getLogin #对应GET /login 的控制器
  • wechatLogin #对应GET /login/wechat的控制器
  • wechatPcLogin #对应GET /login/wechat-pc的控制器

这里为getLogin的控制器,比较简单就渲染一个简单的页面

/** 
* 用户登录页 
* @param req 
* @param res 
* @return {Promise.<void>} 
*/ 
exports.getlogin=async function (req,res) { 
   res.render("jade-html/login") 
}; 

请求层

  • getWeChatToken #获取微信AccessToken
  • getWeChatUserInfo #通过AccessToken获取用户信息

其中的rq为request-promise库

/** 
* 获取微信accesstoken     @see {@link https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842} 
* @param code            微信授权后返回的code 
* @param appid           默认为微信mobile网页登录的appid 
* @param secret          默认为微信mobile网页登录secret, 
* @return {Promise.<void>} 
*/ 
exports.getWeChatToken=async function (code,appid=global.conf.weChatAppId,secret=global.conf.weChatSecret) { 
   //https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 

   let options={ 
       uri: `https://api.weixin.qq.com/sns/oauth2/access_token`, 
       method:'get', 
       qs:{ 
           appid, 
           secret, 
           code, 
           grant_type:"authorization_code" 
       } 
   }; 
   return rq(options); 
}; 

/** 
*  获取微信用户信息              @see {@link https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842} 
* @param access_token          微信的access_token 
* @param openid                微信授权后返回的openid 
* @return {Promise.<void>} 
*/ 
exports.getWeChatUserInfo=async function (access_token,openid) { 
   //https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN 
   let options={ 
       uri: `https://api.weixin.qq.com/sns/userinfo`, 
       method:'get', 
       qs:{ 
           access_token, 
           openid, 
           lang:"zh_CN" 
       } 
   }; 
   return rq(options); 
}; 

视图层

  • login.pug #login登录页

下面是视图层的代码 比较简单,自行引入jquery哈

button.js-wechat 微信登录 
script. 
   $(function(){ 
       $(".js-wechat").on('click',function(){ 

       if($(window).width()>420){ 
           //pc登录 

           let srcPath=encodeURIComponent(`${window.location.origin}${window.conf.path}/login/wechat-pc`); 

           let src=`https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=${srcPath}&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect`; 

           let $html=$(`<iframe width="400px" height="400px" target="_top" src='${src}'></iframe>`); 

           $('body').append($html); 

       }else{ 
           //mobile登录 
           let currentUrl=encodeURIComponent(`${window.location.origin}${window.conf.path}/login/wechat`); 
           window.location.href=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=${currentUrl}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`; 
       } 


})  

   }) 

微信PC登录

微信PC登录一般是扫码登录,文档为微信PC登录文档

首先用户需要访问/login然后点击微信登录按钮,js做判断后直接跳转,注意pc跳转我是使用了iframe 并且特地加上了 这个target=top很重要.ok,从文档中可以得出比较重要的就是那个回调地址

https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=${srcPath}&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect 

也就是其中的redirect_uri 这里需要URI编码后才行 这里我使用的是 /login/wechat-pc, ok再来看看控制器层

微信PC登录之控制器层

 

/** 
* 封装微信登录 
* @param data 
* @param data.code             微信的code 
* @param data.appid            微信的appid 
* @param data.secret           微信的secret 
* @param req 
* @param res 
* @return {Promise.<void>} 
* @private 
*/ 
async function __wechatLogin(data,req,res) { 
   let {code,appid,secret}=data; 

   if(!code){ 
       return res.redirect(`${global.conf.path}/login`); 
   } 

   //获取微信access,token 
   let html=await userRequest.getWeChatToken(code,appid,secret); 
   html=JSON.parse(html); 
   let{access_token,openid}=html; 

   //获取用户信息 
   let wechatUserInfo=await userRequest.getWeChatUserInfo(access_token,openid); 
   wechatUserInfo=JSON.parse(wechatUserInfo); 

   if(!wechatUserInfo||wechatUserInfo.errcode){ 
       return req.redirect(`${global.conf.path}/login`) 
   } 
   res.redirect(`${global.conf.path}`); 
} 

/** 
* 微信Pc扫码登录 
* @return {Promise.<void>} 
*/ 
exports.wechatPcLogin=async function (req,res) { 
   let{query}=req; 

   await __wechatLogin({code:query.code,appid:global.conf.weChatPcAppId,secret:global.conf.weChatPcSecret},req,res) 

}; 

其中global.conf.path=””;这里只是为了方便加前缀 可以把global.conf.path设置为””就好

当用户授权后 微信会跳回刚刚填写的redirect_uri 也就是/login/wechat-pc 这时候微信跳回的地址是这样的xxx.com/login/wechat-pc?code=123456 那么拿到这个code后就可以进行accessToken的替换了,拿到accessToken后就可以获取用户权限了

微信Mobile登录

其实重点在于redirect_uri 那么对应的控制器为

/** 
* 微信mobile登录 
* @return {Promise.<void>} 
*/ 
exports.wechatLogin=async function (req,res) { 
   let{query}=req; 

   await __wechatLogin({code:query.code},req,res) 

}; 

这里我没有传递appid了 因为封装的方法默认会使用mobile的appid和secret当授权成功后就会跳转到首页了 也就是这个 res.redirect(${global.conf.path});