最近思否关注者激增几十人,感觉很是奇怪,想着能够给新关注用户发个问候信息之类。于是便想通过脚本的模式,给用户发送音讯。但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: wxd8936345ec1df5acscope: snsapi_loginredirect_uri: https://segmentfault.com/user/oauth/weixinstate: login_type: jssdkself_redirect: defaultstyletype: 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仅一次无效)

有了该codeSF便能够去微信获取用户数据(当然最重要的是openidunionid)。便可依据该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. 代码实现

内部库:

  • requests: 用于发送申请
  • qrcode_terminal: 用于在Terminal展现二维码

代码详见: https://gist.github.com/lpe234/f5bcb13ec03e3102357844e8a091e92c

执行后果:

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_redirect2022-11-27 18:35:09,103 - sf_wx_login.py - INFO: [获取微信qrcode] 尝试获取uuid2022-11-27 18:35:09,436 - sf_wx_login.py - INFO: [获取微信qrcode] uuid获取胜利 uuid=>0915eXbM1fPC1w3r2022-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=>041MyYZv3QDvEZ2boY3w44ksrY3MyYZf2022-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=>90f96559dc90c6c927752fd905cc3eed2022-11-27 18:35:37,713 - sf_wx_login.py - INFO: [校验token] token无效, hello => lpe234