微信扫码登录二
在上一篇文章 (微信扫码登录) 中,我写了两种扫码登录方式,因为刚开始学习,所以很多不了解,这一篇是在尝试了扫码登录之后,又回过头来进行了总结,并且结合了自己的实例进行了一篇重复性的说明。
1.开放平台方式
开放平台的二维码登录,需要在开放平台中定义相关的应用,上传相关资料后进行审核,审核通过后就可以使用其开放的能力了。登录微信开放平台地址:https://open.weixin.qq.com/ ,点击管理中心->网站应用,可以创建网站应用,也可以创建移动应用。如下图的示例:

创建完相应的应用之后,可以直接构造相应的二维码扫描页面,如浏览器打开地址:https://open.weixin.qq.com/connect/qrconnect?appid=xxx&redirect_uri=xxx&response_type=code&scope=snsapi_login&state=xxx#wechat_redirect
就会直接显示二维码扫描页面。扫描后,页面会直接跳转到 redirect_uri 参数定义的地址上,并且带上code和state参数。至于进一步的获取用户权限,进行比对,可以根据官方的说明:微信登录功能 /网站应用微信登录开发指南 获取access_token,openid等信息,然后自行进行数据权限认证。
2.公众号方式
使用公众号登录的方式,不需要在开放平台中新建应用,但是要实现像开放平台那样的功能,手机扫描pc端的二维码,然后使pc端跳转到一个页面,也是比较麻烦的。
(1) pc端需要使用第三方插件将 授权url地址加上 tempcode (参数名称自定义) 字符串,转换成二维码供用户手机扫描。并且定时轮询后台接口是否扫码授权成功,如果授权成功,还需要进行跳转.
(2) 服务端主要提供的就是授权接口,以及获取用户授权信息之后,将信息临时以参数 tempcode 为标志,保存在内存中,并跳转到显示登录成功的页面。同时还应该提供 tempcode 参数查询是否登录的接口。
(3) 手机端主要就是借助微信,扫描pc端的二维码,然后微信会自动跳转到定义的授权接口,授权接口只需要返回一个html页面,标志用户扫描成功就可以了,最好这个页面是可以自动关闭的。
(1) 创建静态二维码
这一步,主要是在PC端页面,使用qrcode.js 库,这样的二维码生成库,将一串url地址变成一个二维码,这里我用 /index?tempcode=xxx
这个接口代替好了。
(2) 发起授权请求
在 index 这个接口中,需要通过微信提供的 authorize 这个接口,传入相关的 app_id 等信息,构建授权信息请求。
1 | String app_grantscope="snsapi_userinfo"; |
微信扫描上面生成的二维码后,就会直接跳转到 index 这个接口中,然后执行上面的代码,最后会跳转到 redirect_uri 上,并且带上 code和state。上面的代码中,就是跳转到了 “/get_auth_access_token” 这个接口中,并且还附带了我自己定义的一些参数,比如上面的query参数,以及tempcode参数等。
(3) 保存用户信息
在 get_auth_access_token 这个接口中,程序就可以拿到临时code,构造请求地址:```https://api.weixin.qq.com/sns/oauth2/access_token? appid=app_id&secret=app_secret &code= code&grant_type=authorization_code`` 去获取该授权用户的unionid和openid,以及调用的权限的access_token,进一步根据这个 accesss_token,可以获取其他的权限接口信息。获取到用户的openid和unionid之后,可以自行进行权限认证或者是其他的操作,比如可以根据openid比对WxUser表的主键 WxOpenid,是否存在,确定是否给予该用户相应的权限。
为了更加接近于扫码登录,其实我在获取到授权之后,进一步让用户的【手机端】,也就是get_auth_access_token 这个接口,跳转到了一个名为/scan的页面。这个页面的作用就是显示一个扫码成功的信息,并且在五秒后自动关闭自己,这样用户的手机微信页面就回到了信息列表了,看起来就好像扫码成功了一样,如果这个页面不自行关闭,其实也是完成了授权过程,只不过看起来不直观。
tempcode参数的意义,是为了标志用户是否扫码登录的关键。我会根据这个tempcode,将用户扫码后的信息,以及权限比对(主要是数据用户是否有权限查看该数据库)信息保存在缓存中。
(4) 轮询是否授权
在PC端生成二维码的同时,我会有另外的接口 /user/checkloginByCode,查询用户是否扫码登录过了。使用定时轮询的方式,每隔5秒钟,调用该接口,通过传递参数tempcode,也就是上面的 tempcode=xxx ,查看服务器内存中是否已经存在了 xxx 这个临时码的数据,因为有了这个数据,就表明用户已经扫描过了,已经授权过了,没有授权的用户,是无法在内存中生成这个 tempcode 临时码对应的数据的。根据这个特性,这个临时码应该是全局唯一的,并且有时效性,被验证过之后,内存中应该即刻销毁,不再有效。当我获取到了用户的信息之后,就可以让pc端进行跳转了,必要时pc端还需要自行保存用户信息。
也可以用长连接或者是websocket,微信开放平台的二维码扫码登录就是用的长连接的方法,暂时我这里用了轮询的方法,简单方便,但是对服务器压力较大。
(5) 登录后跳转
当使用轮询查询接口 /user/checkloginByCode 返回了用户登录信息之后,就可以在PC端进行跳转了,整个过程也就结束了。
缺点
我突然发现了这种模式的缺点,加入checkloginByCode返回了用户的权限信息,或者是一个token,是不是任何一个人只要是构建了这么一个二维码,让用户扫描了,都可以获取到用户的信息了呢?这样的情况该如何避免呢?
- 接口全部使用https,不允许非法请求
- 关于这个tempcode的生成,可以让服务端生成,类似于解决跨站请求伪造的方法
- 验证HTTP Referer字段
- 提示用户不要扫描非法的二维码
3.共同点
(1)无论使用微信公众号方式进行扫码登录,还是使用开放平台扫码登录方式,都需要根据临时code,换取用户的openid或者是unionid,或者是access_token。
(2)获取到openid之后,还需要进行二次权限的认证,以保证该用户是否有进入该数据库的权限,或者是进入到哪一个数据的权限,目前主要就是和WxUser用户表中的主键WxOpenid进行比对,获取用户的权限信息。