网站使用微信扫码登陆是如何实现自动跳转的?

2020-12-21 11:19:58 +08:00
 asanelder

背景描述

俺看了一下第三方网站使用微信扫码登陆的文档。

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

其实提到,第一步要使用浏览器访问如下链接给出的二维码

https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中 redirect_url 就是要跳转回第三方网站的 URI 。

用户使用微信扫码授权之后,就跳转回了上面的 REDIRECT_URI

问题

用户浏览器访问的是

https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

看这个 URI 似乎和第三方网站无关了,那么,用户在微信授权登录后是如何通知浏览器跳转到 REDIRECT_URI 的呢? 浏览器又是如何知道用户授权了呢?

俺不太会前端,网上搜索了一下,没找到满意的答案,请明白的铁子指点一二!

1919 次点击
所在节点    问与答
8 条回复
linauror
2020-12-21 11:42:30 +08:00
看了下 network,应该是用了长连接轮询的方式,每 15 秒一次
3dwelcome
2020-12-21 11:44:43 +08:00
我简单看了一下,微信官方 JS 是封装成了一个对象,利用 Long polling 服务器推送,来通知浏览器用户已经扫码。
Long polling 就好比客户端发送一个巨大的文件,服务器返回被卡住了,需要很长时间后才会返回结果,但又没有真实的数据进行传输。
qiayue
2020-12-21 11:50:40 +08:00
微信扫码访问 https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 后,微信会返回 302 让浏览器跳转到 REDIRECT_URI,同时附加上 code 。
REDIRECT_URI 这里接收到 code 之后,调用微信接口去判断 code 是否有效,如果有效则获取用户信息,同时做注册或者登录处理,之后往缓存中记录一个值。

而显示二维码给用户的前端页面,则不断向后端轮询,查看缓存中是否有匹配的值 ,有则说明登录了。
opengps
2020-12-21 11:52:31 +08:00
或者密集短轮询,或者直接长连接,客户端通知只能这么搞
killergun
2020-12-21 12:42:50 +08:00
扫码完了,微信会跳转到 redirect_uri 指定的服务上(这个服务是应用方,这个是后端),这个时候微信会在返回 code,根据应用方可以向微信请求获取用户信息,获取成功后,应用方再跳转到自己服务带上用户信息就行了。这个时候就是登录成功了
indo
2020-12-21 14:43:13 +08:00
这两天刚做这个。
前端在页面打开的时候同时创建一个长链接向服务器发起请求,请求时携带的参数跟微信的 state 参数一致。
在微信的 redirect_url 处理时将 state 值写入到缓存中。再前端页面的长链接请求的后端地址中写一个循环去查询缓存中的 state 值,如果查询到了就返回确认参数从而让前端页面自动跳转。
indo
2020-12-21 14:48:34 +08:00
```php
//这里的 login 用来给微信回调使用
public function login()
{
$code = Request::param('code');
if ($code) {
//TODO 用户同意授权
(new Token())->saveToken();
} else {
//TODO 用户拒绝授权
Token::rejectLogin(Request::param('state'));
}


}
//这里的 checkLogin 是给前端的创建的长链接来检查登录状态的
public function checkLogin()
{
$token = Request::post('token');
while (true) {
$temp = Cache::get($token);
if ($temp) {
switch ($temp['isLogin']) {
case 1:
$res = [
'isLogin' => 1,
'msg' => '登陆成功'
];
return json($res);
case 0:
$res = [
'isLogin' => 0,
'msg' => $temp['msg']
];
return json($res);
}
}
}
}
```

```javascript
$.ajax({
url:url,
data:{
'token' : guidStr
},
method:'POST',
timeout:60000,
success:function (res) {
if (res.isLogin === 1 )
{
layui.data(setter.tableName,{key:setter.request.tokenName,value: guidStr});
layer.msg(res.msg,{icon: 1,time: 1000},function () {
location.href = url;
})
}
if(res.isLogin === 0 )
{
layer.msg(res.msg,{icon:2,time:1000},function () {
location.href = 'https://www.baidu.com';
})
}
},
error:function () {
layer.msg('登陆超时,请重新刷新页面后再试。',{icon:0},function (){
location.reload();
})
}
})
```
asanelder
2020-12-21 18:29:27 +08:00
@linauror #1
@3dwelcome #2
@killergun #5
@opengps #4
@qiayue #3

感谢提供思路,俺看看

@indo #7 nice 啊,铁子,细节代码都给出来了,俺学习学习思路

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/737425

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX