微信网页授权,错误40163,ios正确,安卓错误?

发布于 2022-09-05 08:12:03 字数 1335 浏览 12 评论 0

点击一个公众号菜单,跳转到【微信网页授权】,ios平台没问题,安卓平台始终是错误40163,官方的说法是code被重复使用了,从index.php里获取了马上就跳转到oauth.php里去换取access_token,中间没有任何使用过!看到网上一条线索,用苹果手机没任何问题,安卓一直是错误40163,换了两台安卓设备,微信都更新到了最新版本,错误一直在~

代码如下:

index.php

<?php
header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appid.'&redirect_uri='.$myappurl.'oauth.php&response_type=code&scope=snsapi_userinfo&state=1&connect_redirect=1#wechat_redirect');

oauth.php

<?php
    $code = $_GET['code'];
    $state = $_GET['state'];

    
    if (empty($code)) $this->error('授权失败');

    //获取oauth_token
    $token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code';
    $token = json_decode(file_get_contents($token_url));
    if (isset($token->errcode)) {
        echo '<h1>错误:</h1>'.$token->errcode;
        echo '<br/><h2>错误信息:</h2>'.$token->errmsg;
        exit;
    }

   //……

图片描述

图片描述

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

居里长安 2022-09-12 08:12:03

2018-07-18:一年时间过去了,我又回来填自己挖的坑了!!

2017年7月,我遇到了这个问题,当时在这里提了问,后来又跟踪了两天,也没彻底搞懂,反正时好时坏,,后来自己主要精力放在H5+开发上,就不怎么关心公众号这块了;

2018年7月,我又带着python重回公众号,又遇到了这个问题,这次绕不过去了,一年过去了,网上搜索一下,问这个问题的人还是很多,而且也没有真正解决这个问题,

比如这条:https://developers.weixin.qq....

再比如:https://blog.csdn.net/hejisan...

其实这个问题也不复杂,总结起来说,就是“点击公众号菜单产生两次请求”,导致code被用了两次,但是因为微信官方的文档没有相关内容,大家也都用自己的方式解决,我的解答应该也只是其中一种吧。

有人说:“后来发现只要加个属性就不会有这个问题了。

https://open.weixin.qq.com/co...connect_redirect=1#wechat_redirect

&connect_redirect=1 这个参数”

!很可惜,这条加上去,对我一点也不起作用!

又仔细阅读微信官方的文档https://mp.weixin.qq.com/wiki...
这里有
appid
redirect_uri
response_type
scope
state
wechat_redirect
的作用说明,但是并没有上面提到的connect_redirect,

提到了一个state的参数,这个是干嘛用的呢?
/////////////////////////////
state 否 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
/////////////////////////////

测试的时候发现,在访问https://open.weixin.qq.com/co...,无论state填什么,获取code的时候,这个字段会原样返回过来,好就用它来解决。

既然这个参数会被原样返回过来,那我就利用它作为一个令牌,发送之前先生成一个随机数,然后保存到一个全局变量里,在redirect_uri页面的接收到这个随机数,跟全局变量对比一下,如果一样,就把这个令牌改掉,这样第二次访问的时候,这个令牌就失效了,就pass掉这个请求,避免了被2次访问的情况。

PS.
纯php没有全局变量,用一些框架应该就会有,或者写到session或者缓存都行;
我是在django里开发的,所以就直接搞了个全局变量,简单粗暴。
我是python初学者,代码写得比较拖沓啰嗦,见谅。
有人说是微信内置浏览器的问题,也有人说是nginx的问题,我觉得应该不是nginx,因为这次用python用的是django内置的服务器,也同样情况。这个问题在苹果手机上好像就没有,主要是在安卓版微信上有,因为自己已经不用苹果手机了,所以也没有做测试。

最后,上代码:

我的开发环境:
python 3.5.3
django 2.0.7

view.py代码如下:

import json
import random
import requests

#全局变量
APP_ID          = '公众号ID'
App_SEC         = '公众号SEC'
RADOM_STATE     = ""

def oauth(request):

    global RADOM_STATE

    _code = request.GET

    #1 第一步,拿到code
    oauth_state = _code['state']
    oauth_code = _code['code']
    oauth_info_json = {
        'oauth_state' : oauth_state,
        'oauth_code' : oauth_code
    }
    #print("=====>" + json.dumps(oauth_info_json))


    print(oauth_state)    #本次拿到的随机数令牌
    print(RADOM_STATE)    #全局变量里保存的跳转之前生成的随机数令牌

    #比较本次state和全局随机数令牌是否一致,不一致,说明是第二次访问,丢弃
    if RADOM_STATE != oauth_state:
        pass
    else:
        #一致,重新生成随机数令牌,防止第二次访问造成code失效
        RADOM_STATE = str(random.randint(1000, 9999))
        # print(RADOM_STATE)

        # 2 第二步, 换取access_token
        url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type=authorization_code'.format(APP_ID, App_SEC, oauth_code)
        print(url)
        oauth_access_token = requests.get(url)
        print("=====>" + oauth_access_token.text)
        re_json_str = oauth_access_token.text
        # print(type(re_json_str), re_json_str)
        re_json = json.loads(re_json_str)
        # print(type(re_json), re_json)



        # 3 第三步,拿到用户信息
        try:
            url = 'https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang=zh_CN'.format(re_json['access_token'], re_json['openid'])
            print(url)
            user_info = requests.get(url)
            #print(user_info.encoding)
            #print(user_info.text.encode("iso-8859-1").decode('utf8'))

            user_info_json_str = user_info.text.encode("iso-8859-1").decode('utf8')            #微信传过来的中文使用的iso8859编码,为了在模板里能显示出来,要转换成utf8编码
            # print(type(user_info_json_str), user_info_json_str)

            user_info_json = json.loads(user_info_json_str)
            # print(type(user_info_json), user_info_json)

        except Exception as e:
            print(e)


        #把数据给html模板,其实oauth_info_json没必要传了,
        #只需要user_info_json就够了,这里只是为了演示!
        #或者提取了user_info之后做各种业务逻辑操作都可以!


        content = {
            'oauth_info': oauth_info_json,  #oauth_info_json
            'user_info': user_info_json     #user_info_json
        }
        return render(request, 'user_info.html', content)    







def user_info(request):

    global RADOM_STATE

    REDIRECT_URI = "http://www.xxxxxxxxx.cn/weixin/oauth/"         #跳转的地址
    SCOPE = "snsapi_userinfo"
    STATE = str(random.randint(1000,9999))        #生成随机数
    RADOM_STATE = STATE                            #随机数给全局变量
    redirect_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}&response_type=code&scope={}&state={}&connect_redirect=1#wechat_redirect".format(APP_ID, REDIRECT_URI, SCOPE, STATE)
    # print(redirect_url)
    return HttpResponseRedirect(redirect_url)    #向微信服务器做跳转

user_info.html模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>yoooko.cn</title>
</head>
<body>

    <h1>Hello</h1>
    <h3>oauth_state: </h3><p>{{ oauth_info.oauth_state }}</p>
    <h3>oauth_code: </h3><p>{{ oauth_info.oauth_code }}</p>

    <p><b>{{ user_info }}</b></p>


</body>
</html>

2017-07-29:结贴
昨天研究了半天,也没解决,看到出错的http头里面有PHPSESSID,回头去修改了一下程序里的session部分的代码(这部分代码在微信网页授权之后),,也不知道是腾讯那边修正了bug还是我修改了正确的session代码,反正这个问题没了,已经正常运行了一天了~

2017-07-28:第三次更新
加了https之后,就我自己调试的那个账号的安卓设备可以了,其他账号还是会出现问题,而且这次不出错误40163了,压根白页面,过会儿出现网页找不到,复制链接一看还在index.php里,压根不转入oauth.php了,看来问题的确是在公众号后台那边。

不用https,用日志记录,确实oauth.php被调用了两次,http头记录如下:

error

2017-07-27 14:48:29 【021HVeVO1RRzU31O5ZXO1LdhVO1HVeVe】

2017-07-27 14:48:29 【{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/wxpic,image/sharpp,/;q=0.8","Accept-Encoding":"gzip","Accept-Language":"zh-CN,en-US;q=0.8","Connection":"close","Cookie":"PHPSESSID=2nogkq0l072jvnt8728jonned4","Host":"www.yoookosoft.cn","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; MI 4LTE Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043409 Safari/537.36 MicroMessenger/6.5.10.1080 NetType/WIFI Language/zh_CN","X-Forwarded-For":"114.231.66.45"}】

2017-07-27 14:48:39 【021HVeVO1RRzU31O5ZXO1LdhVO1HVeVe】

2017-07-27 14:48:39 【{"Host":"www.yoookosoft.cn","Connection":"keep-alive","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (Linux; Android 6.0.1; MI 4LTE Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043409 Safari/537.36 MicroMessenger/6.5.10.1080 NetType/WIFI Language/zh_CN","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/wxpic,image/sharpp,/;q=0.8","Accept-Encoding":"gzip, deflate","Accept-Language":"zh-CN,en-US;q=0.8","Cookie":"PHPSESSID=2nogkq0l072jvnt8728jonned4"}】


ok

2017-07-27 14:50:05 【001zXCac2zuXTQ0f747c2CFAac2zXCam】

2017-07-27 14:50:05 【{"Host":"www.yoookosoft.cn","Upgrade-Insecure-Requests":"1","Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8","User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89 MicroMessenger/6.5.10 NetType/WIFI Language/zh_CN","Accept-Language":"zh-cn","Accept-Encoding":"gzip, deflate","Connection":"keep-alive"}】

暂时还没解决办法,今天继续排查~

2017-07-26: 第二次更新
并未彻底解决
各种方法解决不了之下,又继续读公众号的官方文档https://mp.weixin.qq.com/wiki...,读到这一部分

“授权后重定向的回调链接地址,请使用urlEncode对链接进行处理”
官方的例子就是用urlEncode的,马上改成urlEncode,但是错误依旧;

“尤其注意:跳转回调redirect_uri,应当使用https链接来确保授权code的安全性。”
再看官方的跳转地址,第一个snsapi_base是有https的,第二个snsapi_userinfo没有用https,我的服务器上是有部署https的,马上在http后面加了个s,我靠,问题解决了!!!安卓也再没有错误40163了,苹果为什么没事呢?苹果的app是强制使用https的,安卓没有强制!!!为什么每次刚重启服务器的时候安卓好用的呢?现在的网络环境太差了,谁知道在传输过程中被加了些什么?看来https真的是有必要大力推广!!!

以下是官方的例子:

scope为snsapi_base

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdap
ter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_bas
e&state=123#wechat_redirect 

scope为snsapi_userinfo 

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=
code&scope=snsapi_userinfo&state=STATE#wechat_redirect 

2017-07-26:第一次更新

我又在header之前加了不使用缓存,强制不使用缓存,还是有这个错误~

    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    header("Cache-Control: no-cache");
    header("Pragma: no-cache");
    header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$appid.'&redirect_uri='.$myappurl.'oauth.php&response_type=code&scope=snsapi_userinfo&state=1&connect_redirect=1#wechat_redirect');

然后找了【微信web开发者工具】,在pc上模拟访问微信网页授权,这次发现点线索,照理说用snsapi_userinfo方式访问微信网页授权(如果是snsapi_base是不会出现下面的窗口的),会跳一个授权窗口,

clipboard.png

如果近期已经授权过,就出这个画面
图片描述

我怀疑是不是跟这里有关,在安卓手机上现在不显示上述提示窗口了,然后进度条走了很长时间之后,就开始出错误40163,在【微信web开发者工具】上是会出现提示窗口的!感觉应该是微信安卓版的问题,但是微信又没有什么可以提问的平台,微信客服形同虚设,真郁闷。

clipboard.png


我想了个不太靠谱的方案,不知道是否可行,,如果我拦截到错误40163,就再去访问一次index.php,再去获取一次code,再回到oauth.php处理,尝试3次,如果还是出现,就给个错误页面,,但是估计可能没用,一旦出现了40163,就会一直出现这个错误,周六上午一直出这个错,但是今天周一,安卓又好的

猜测是公众号后台那边遇到了阻塞?处理安卓和ios请求的是不同的服务器,进了不同的处理队列,但是后端一般应该是不会区分是来自什么平台发送的请求,应该是一视同仁处理请求的吧~

只为一人 2022-09-12 08:12:03

应该是auth.php被刷新了一次,导致code第二次使用失败。你写个日志记录一下,看看是不是这个情况

最丧也最甜 2022-09-12 08:12:03

这是我刚用过的code换取access_token,你参考下

<?php
    $data=[];
    $data['appid']=$appid;
    $data['secret']=$appsecret;
    $data['code']=$code;
    $data['grant_type']='authorization_code';
    $url="https://api.weixin.qq.com/sns/oauth2/access_token";

    $token_res=getRequest($url,$data);
    if(false===$token_res){
        //错误处理
    }

    $token_arr=json_decode($token_res,true);
    if(!isset($token_arr['access_token']) || !isset($token_arr['openid'])){
        //错误处理
    }
    
    function getRequest($url='',$data=[])
    {
        if(empty($url)){
            return false;
        }
        if(!is_array($data)){
            return false;
        }

        if(!empty($data)){
            $query=http_build_query($data);
            $url=$url.'?'.$query;
        }

        //初始化
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        //设置请求的url
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT , 15 );
        curl_setopt($curl, CURLOPT_TIMEOUT , 15);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

        //执行命令
        $response = curl_exec( $curl );
        if ($response === false) {
            return false;
        }
        //关闭URL请求
        curl_close($curl);
        return $response;
    }
?>
人心善变 2022-09-12 08:12:03

建议抓包看看。到底跳转了几次。是不是有别的地方有代理当ua是安卓的时候会在跳转一次。

红ご颜醉 2022-09-12 08:12:03

请问问题解决了吗?现在我也遇到这个问题很多的4 0 1 6 3错误,是h tt ps问题还是微信服务器后台问题?

空城之時有危險 2022-09-12 08:12:03

请问您的问题解决了吗?我也遇到这个问题,您是怎么解决的呢?

和我恋爱吧 2022-09-12 08:12:03

老哥 解决了吗 昨天做授权登录也出现这个问题 之前做了很多公众号都没问题 真是奇怪
你说的这个重新获取code估计不靠谱 code有效时间是五分钟吧 不失效获取的还是同一个 而且也不能确保重新获取后不再重复访问
我的问题也是会访问两次redirect_url 第一次成功登录了都 然后不知道什么情况又访问一次。。就报40163了,醉了
准备用session把第一次获取的用户信息缓存下来,然后第二次请求获取errcode 判断 再跳转页面。。但是 第二次尽然获取不到session。。。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文