前言
实习过程中,我参与了web版相册管家的开发,负责登陆页面的前后端逻辑。
需要在登陆页接入QQ互联和微信扫码登陆,而且是用页面内嵌方式。回头来看其实两者都有文档指导,步骤清楚,并不复杂。但是第一次接触难免踩坑,在此梳理如下,方便今后开发参考。
QQ互联
开发文档 https://wiki.connect.qq.com/%E7%BD%91%E7%AB%99%E5%BA%94%E7%94%A8%E6%8E%A5%E5%85%A5%E6%B5%81%E7%A8%8B
应用申请
申请appid和appkey
- appid:应用的唯一标识。在OAuth2.0认证过程中,appid的值即为oauth_consumer_key的值。
appkey:appid对应的密钥,访问用户资源时用来验证应用的合法性。在OAuth2.0认证过程中,appkey的值即为oauth_consumer_secret的值。
- 申请地址: https://connect.qq.com/manage.html#/
tip: 申请时注意网站回调域必须为网站地址下的子目录,用户授权后页面会跳转到这个回调地址,通常情况下我们需要取得该地址的code参数进行后续接入流程,所以要保证该地址中的代码可控。
授权登陆流程
本文中列出的是server-side模式的登陆流程,client-side模式可参考 https://wiki.connect.qq.com/%E5%BC%80%E5%8F%91%E6%94%BB%E7%95%A5_client-side
Step 1 获取Authorization Code
- 浏览器访问授权页地址:https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=[YOUR_APPID]&redirect_uri=[YOUR_REDIRECT_URI]&scope=[THE_SCOPE]
- 参数列表如下,把client_id、redirect_uri、scope按照列表修改
tip:redirect_uri必须与注册应用的时候填的回调域一样,该项在申请通过后可以在qq互联应用管理处修改,无需再次审核。
http://localhost:3000/proxy?code=D21B82BA835586D8DF86135675EC71BD
此时,从url中取得code,进行下一步。
tip:该code会在10分钟内过期,且无法重复使用
Step 2 通过Authorization Code获取Access Token
请求地址:
https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=[YOUR_APP_ID]&client_secret=[YOUR_APP_Key]&code=[The_AUTHORIZATION_CODE]&redirect_uri=[YOUR_REDIRECT_URI]
参数表为:- 请求方法:GET
- 如果请求成功,返回值的body里面会包括access_token=FE04*CCE2&expires_in=7776000&refresh_token=88E4*BE14,可从中取得access_token
- tip 1: 返回值为字符串,不是json对象,需要自己拆分
- tip 2: 参数中的redirect_uri在此并不涉及跳转,只做验证
tip 3: 若想实现权限自动续期,参考 https://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token#Step2.EF.BC.9A.E9.80.9A.E8.BF.87AuthorizationCode.E8.8E.B7.E5.8F.96AccessToken
Step 3 使用Access Token 获取用户openid/unionid
- 请求地址: https://graph.qq.com/oauth2.0/me?access_token=ACCESSTOKEN&unionid=1
- 请求方法:GET
- 请求参数: 上一步获取的 access_token(必需)unionid(非必需),标识是否申请unionID
- 请求成功返回值:
callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID","unionid":"YOUR_UNIONID"} );
- tip: 返回值为一个带callback的字符串,非对象,需要自己拆分。
Step 4 使用用户OpenID获取用户信息
使用access_token, appid, openid调用get_user_info接口,可获取用户信息。
接口文档见: https://wiki.connect.qq.com/get_user_info
iframe 内嵌登陆框实现
我找了一圈,没发现qq互联有可以自定义生成登陆界面或者登陆二维码的操作(微信有),参考了几个内嵌登陆的网站,发现大家的UI和大小都是固定的,猜想应该是通过iframe截取实现的,官方给的demo也是类似思路。
于是我自己琢磨着用iframe截取授权登陆页面,然后通过iframe向父页面传值拿到code。怎么想这么搞都挺笨的,奈何没找到更简单的方法,抛砖引玉,如果有更方便的思路麻烦告知。
内嵌iframe,局部定位
- iframe局部定位有很多种方法,我这里采取的是用多个div来截取的方式,调整起来比较灵活,大家用自己喜欢的方式就行。
- tips: 截取时的范围需要考虑鼠标悬停时会浮现的提示框,以及扫码后的提示界面文字的范围,不只是图标范围,截取太小会导致被遮挡。
父子页面传值,获取code
- 在登陆授权后,iframe内会跳转到带着code参数的,我们申请的回调页面。在该回调页面内,从url中取得code,并传给父页面,即我们的登陆页面。
- vue框架下的代码如下,思路都差不多
mounted() {
let codeUrl = window.location.href;
let code = this.getCode(codeUrl)
this.sendLoginCode(code)
},
methods: {
// 拆分url获取code
getCode(url) {
if (url.indexOf('code') !== -1) {
let params = url.split('?')[1].split('&')[0].split('=')[1];
return (params);
}
},
// 发送给父页面
sendLoginCode(code) {
window.parent.postMessage({
type: "sendCode",
data: code
}, '*');
},
}
- 在父页面对iframe的传值进行监听,拿到code之后就一切好说,按照前述流程去后端获取用户信息就好了
// 监听iframe的返回 window.addEventListener('message', (e) => { console.log(e,e.data) let data = e.data; if(data && data.type && data.type == 'sendCode') { let code = data.data; this.getUserInfo(code) } }, false);
微信扫码登陆
开发文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=56b86cbd4aafb4deaceaf5385b567d5e7191102d&lang=zh_CN
应用申请
- 在微信开放平台进行应用申请,与qq互联的应用申请相似
tip:注意!!! 微信应用的回调域和qq互联的不同,举个例子,你的网站是http://a.com, qq互联的回调域只能是你申请时填写的http://a.com/login。但是,微信申请时的授权回调域填写你的主域名即可,因为
如果你申请微信的回调域也填写http://a.com/login,在生成授权页面时redirect_uri使用http://a.com/login会报错,并不能生成授权页面。
授权登陆流程
微信的授权登陆流程与QQ互联基本相同,区别在于code以及access_token的有效期,以及code可以直接换取access_token+openid,在此不再赘述,具体流程和接口可参考开发文档,以及接口文档 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316518&lang=zh_CN
内嵌二维码
JS实现以及样式调整
- 微信为前端提供了直接可以通过JS实现二维码生成的方法(感谢微信!!)
先在页面中引入js文件(支持https)
http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
- 在需要使用微信登陆的地方实例化以下JS对象
var obj = new WxLogin({
self_redirect:true,
id:"login_container",
appid: "",
scope: "",
redirect_uri: "",
state: "",
style: "",
href: ""
});
- 这里的href参数可以自定义扫码样式,一种据说是引入一个https地址的css文件例如:href: "https://lws.com/test.css",由于没有配置https所以没有实践,另一种是把样式代码进行base64加密放到href参数中。
- 微信提供的样式代码如下
.impowerBox .qrcode {width: 200px;}
.impowerBox .title {display: none;}
.impowerBox .info {width: 200px;}
.status_icon {display: none}
.impowerBox .status {text-align: center;}
按照自己的需求修改调整后,将样式代码转为base64加密,放入代码,这里我用的站长工具,大家自由发挥。
- 然后将用如下href实例化JS对象就可以了,二维码大小即可自由调整~
href:"data:text/css;base64,[加密后的样式代码]"
code拿取
- 其实微信js对象生成的二维码,也是个iframe,扫码后还是会跳转到你传入的回调地址,由于url形式和qq互联相同,我这里和qq互联使用的是相同的回调地址,采用和qq互联相同的方式即可取到code。