开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
最近思否关注者激增几十人,感觉很是奇怪,想着可以给新关注用户发个问候信息之类。于是便想通过脚本的形式,给用户发送消息。但token获取是个问题,便想着也用脚本自动化。用户名密码登录会有验证码。那就使用微信第三方登录吧,正好巩固下OAuth。
1. 分析整个登录流程
Chrome隐私模式下,打开开发者模式,再打开https://segmentfault.com/。
1.1 微信OAuth2.0授权地址获取
可以看到,默认登录方式就是微信登录。而微信OAuth地址获取入口为固定URL。这个同样也可以在JS源码中找到umi.js。
地址为: https://segmentfault.com/gateway/session/oauth/weixin/redirect?is_mobile=0
再看该请求的返回数据:
{
"redirect_url":"https:\/\/open.weixin.qq.com\/connect\/qrconnect?appid=wxd8936345ec1df5ac&redirect_uri=https%3A%2F%2Fsegmentfault.com%2Fuser%2Foauth%2Fweixin&response_type=code&scope=snsapi_login#wechat_redirect"
}
得到redirect_url为: https://open.weixin.qq.com/connect/qrconnect?appid=wxd8936345ec1df5ac&scope=snsapi_login&redirect_uri=https://segmentfault.com/user/oauth/weixin&state=&login_type=jssdk&self_redirect=default&styletype=&sizetype=&bgcolor=&rst=&href=https://s.segmentfault.com/css/weixin.css
我们解析一下该URL的参数:
appid: wxd8936345ec1df5ac
scope: snsapi_login
redirect_uri: https://segmentfault.com/user/oauth/weixin
state:
login_type: jssdk
self_redirect: default
styletype:
sizetype:
bgcolor:
rst:
href: https://s.segmentfault.com/css/weixin.css
可以发现,其实不通过SF提供的地址也是可以的。至此已得到授权地址。
1.2 登录二维码获取
在Chrome上,会自动展示二维码。下面咱们分析下二维码的来源及展示内容。在浏览器上单独访问上文的redirect_url。
先看下二维码的地址。https://open.weixin.qq.com/connect/qrcode/0913LA3008yh0w3q。在看下原始网页中的内容。
我们可以发现,这一串内容在他们内部叫做uuid。只要拿到这个uuid就能拿到二维码。
在看一下二维码里面具体的内容。
https://open.weixin.qq.com/connect/confirm?uuid=031J67qn4WUy0w3b
可以看到,这个confirmURL唯一重要的参数就是uuid。拿到了UUID就拿到了二维码。
1.3 扫描结果在哪里
可以看到页面一直在做长轮询,间隔为15秒。返回结果:
window.wx_errcode=408;window.wx_code='';
地址为: https://lp.open.weixin.qq.com/connect/l/qrconnect?uuid=031J67qn4WUy0w3b&_=1669547560624
参数:
uuid: 为授权请求二维码_: 时间戳 (应该是避免缓存之类)
经过多次尝试分析发现。
目前已知wx_errcode:
- 402:二维码过期
- 404:已扫码(未操作)
- 405:扫码确认登录(有wx_code返回)
- 408:未扫码(初始状态)
- 初始值一直为
408,然后长轮询。 - 当用户扫码后,返回值变为
404,此时请求参数需要增加last=404继续为止长轮询。 - 当用户确认后,返回
405,此时wx_code会有值。也就是OAuth协议中最重要的code(该code仅一次有效)
有了该code,SF便可以去微信获取用户数据(当然最重要的是openid和unionid)。便可根据该openid获取到关联的用户,并生成该用户的token并返回给前端。
1.4 登录接口(code换token)
1.4.1 方式一
在Chrome开发者工具中,可以看到请求:https://segmentfault.com/user/oauth/weixin?code=011hcEml2K03ka5gEWll2UUfkI0ckHQR&state=。在其响应头中可以看到有set-cookie: PHPSESSID。该PHPSESSID即为token。
1.4.2 方式二
在Chrome开发者工具中,可以看到请求https://segmentfault.com/gateway/session/oauth/weixin/user。参数为:
{
"type": "weixin",
"code": "011hcEml2K03ka5gEWll2UUfkI0ckHQR"
}
但是该接口却没有任何响应体及有效响应头。但通过不请求方式一仅请求该接口时发现,响应头中有set-token响应头,而内容即为token。
2. 代码实现
2.1 整体思路
- 根据SF的微信第三方登录固定地址,拿到OAuth授权地址
- 根据OAuth授权地址,拿到二维码(
uuid) - 展示二维码,并长轮询结果,尝试获取
wx_code - 拿到
wx_code,根据SF授权地址,获取token/PHPSESSID
2.2 代码
外部库:
- requests: 用于发送请求
- qrcode_terminal: 用于在Terminal展示二维码
代码详见: gist.github.com/lpe234/f5bc…
掘金code: code.juejin.cn/pen/7170869…
注:这种代码在掘金code是没办法运行的。
- ①官方有支持Python,但现在似乎还没放开。
- ②安装依赖包是个问题,不过像
requests这种依赖包已经存在了,但像qrcode_terminal这种不是很热门的不知道咋引入。(可能存在一些安全问题) - ③无法发起外部访问。(当然如果支持,绝对是很大的安全隐患)
2.3 执行结果
2022-11-27 18:35:08,949 - sf_wx_login.py - INFO: [获取微信redirect_url] 尝试获取
2022-11-27 18:35:09,103 - sf_wx_login.py - INFO: [获取微信redirect_url] 获取成功 url=>https://open.weixin.qq.com/connect/qrconnect?appid=wxd8936345ec1df5ac&redirect_uri=https%3A%2F%2Fsegmentfault.com%2Fuser%2Foauth%2Fweixin&response_type=code&scope=snsapi_login#wechat_redirect
2022-11-27 18:35:09,103 - sf_wx_login.py - INFO: [获取微信qrcode] 尝试获取uuid
2022-11-27 18:35:09,436 - sf_wx_login.py - INFO: [获取微信qrcode] uuid获取成功 uuid=>0915eXbM1fPC1w3r
2022-11-27 18:35:09,437 - sf_wx_login.py - INFO: [获取微信qrcode] 准备渲染
[ ]
qr
[ ]
2022-11-27 18:35:10,469 - sf_wx_login.py - INFO: [长轮询登录结果] 开始轮询
2022-11-27 18:35:25,639 - sf_wx_login.py - INFO: [长轮询登录结果] 依旧未扫码,继续轮询
2022-11-27 18:35:28,107 - sf_wx_login.py - INFO: [长轮询登录结果] 已扫码,等待用户确认
2022-11-27 18:35:36,811 - sf_wx_login.py - INFO: [长轮询登录结果] 已扫码确认
2022-11-27 18:35:36,811 - sf_wx_login.py - INFO: [长轮询登录结果] 已扫码确认 wx_code=>041MyYZv3QDvEZ2boY3w44ksrY3MyYZf
2022-11-27 18:35:36,812 - sf_wx_login.py - INFO: [登录sf] 尝试登录
2022-11-27 18:35:37,378 - sf_wx_login.py - INFO: [登录sf] 返回数据 resp=>{'type': 'login', 'msg': '登录成功'}
2022-11-27 18:35:37,378 - sf_wx_login.py - INFO: [登录sf] 成功获取token token=>90f96559dc90c6c927752fd905cc3eed
2022-11-27 18:35:37,713 - sf_wx_login.py - INFO: [校验token] token有效, hello => lpe234