最近思否关注者激增几十人,感觉很是奇怪,想着可以给新关注用户发个问候信息之类。于是便想通过脚本的形式,给用户发送消息。但token获取是个问题,便想着也用脚本自动化。用户名密码登录会有验证码。那就使用微信第三方登录吧,正好巩固下OAuth。

1. 分析整个登录流程

Chrome隐私模式下,打开开发者模式,再打开https://segmentfault.com/

1.1 微信OAuth2.0授权地址获取

image.png

可以看到,默认登录方式就是微信登录。而微信OAuth地址获取入口为固定URL。这个同样也可以在JS源码中找到umi.js

image.png

地址为: 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

image.png

先看下二维码的地址。https://open.weixin.qq.com/connect/qrcode/0913LA3008yh0w3q。在看下原始网页中的内容。

image.png

我们可以发现,这一串内容在他们内部叫做uuid。只要拿到这个uuid就能拿到二维码。

在看一下二维码里面具体的内容。

https://open.weixin.qq.com/connect/confirm?uuid=031J67qn4WUy0w3b

可以看到,这个confirmURL唯一重要的参数就是uuid。拿到了UUID就拿到了二维码。

1.3 扫描结果在哪里

image.png

可以看到页面一直在做长轮询,间隔为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。

image.png

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_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

echo '5Y6f5Yib5paH56ugOiDmjpjph5Eo5L2g5oCO5LmI5Zad5aW26Iy25ZWKWzkyMzI0NTQ5NzU1NTA4MF0pL+aAneWQpihscGUyMzQp' | base64 -d

lpe234
4.1k 声望2k 粉丝

路漫漫其修远兮