解决QQ登录SDK不能网页授权登录的问题

Android 专栏收录该内容
18 篇文章 0 订阅

现象

QQ登录SDK在用户设备没有安装手机QQ客户端的情况下,默认是会调起网页授权的,但是可能是因为腾讯的某些限制,新申请的app_id都无法使用网页授权,打开后有些是跳转到下载手Q页面,有些是一直显示“正在打开授权登录页…”

分析

试了下市场上其他app使用QQ登录的情况,发现京东的客户端,在未安装客户端的情况下是可以打开网页授权的,抓包得到京东的授权链接:

http://openmobile.qq.com/oauth2.0/m_authorize?status_os=5.0.2&client_id=100273020&status_userip=fec0%3A%3A10%3A5530%3Aabe3%3Abbb9%3Ac98e%2516&format=json&switch=1&status_version=21&appid_for_getting_config=100273020&status_machine=x600&pf=openmobile_android&sdkp=a&sdkv=2.4.lite&sign=88d1d495ffc03ae69a9339367172a5bf&time=1467062773&scope=all&redirect_uri=auth%3A%2F%2Ftauth.qq.com%2F&display=mobile&response_type=token&cancel_display=1

同时在网上找到一个介绍说不用SDK直接打开网页授权的链接:

https://openmobile.qq.com/oauth2.0/m_authorize?status_userip=&scope=add_share,add_topic,list_album,upload_pic,get_simple_userinfo&redirect_uri=auth%3A%2F%2Ftauth.qq.com%2F&response_type=token&client_id=100353810

这个链接也是能打开授权页的,但是参数比较少。

那么问题来了,腾讯到底是怎么限制是否能打开授权登录页的呢?
尝试使用我们自己的app_id替换链接中的client_id,发现第二个链接竟然也能打开,那么也就是说应该不是根据app_id来做的限制,那就可能是其他参数了。因此人肉一个个的测试,最终发现是根据sdkv这个参数来做限制的。

那么这个值该改成多少呢?

查看了QQ互联SDK的更新记录:

V1.6 更新了如下内容:
1.登录方式支持手机QQ登录。
2.支持通过手机QQ分享信息。
3.PCPUSH增加手机QQ渠道触达。

V1.6才支持手Q登录,那么之前的sdk应该都是网页授权咯?测试下,最终发现版本号1.4及以下的版本都能打开授权登录页。好了,万事俱备,只欠东风。

解决方案

通过字符串查找拼接网页授权url的地方,然后通过反射的方式来修改这个网页授权的url就ok了,具体步骤不展开了,代码如下:

以下方案是基于3.1.0lite

    /**
     * 解决网页授权问题
     *
     * @return true: 成功; false: 失败
     */
    private boolean fixWebAuth(Context context, Tencent tencent) {
        if (AppUtils.isAppInstalled(context.getApplicationContext(), "com.tencent.mobileqq")) {
            return true;
        }
        if (tencent == null) {
            return false;
        }
        boolean ok = false;
        try {
            Field aField = tencent.getClass().getDeclaredField("a");
            aField.setAccessible(true);
            Object cVal = aField.get(tencent);
            Field authAgentField = cVal.getClass().getDeclaredField("a");
            authAgentField.setAccessible(true);
            authAgentField.set(cVal, new FixWebAuthAgent(tencent.getQQToken()));
            ok = true;
        } catch (Throwable ignore) {
        }
        return ok;
    }
    /**
     * 解决网页授权问题的AuthAgent
     */
    private static class FixWebAuthAgent extends AuthAgent {

        FixWebAuthAgent(QQToken qqToken) {
            super(qqToken);
        }

        @Override
        protected Bundle a() {
            Bundle bundle = super.a();
            if (bundle != null) {
                // 主要原因在这, 腾讯的server估计是判断这个版本号来进行限制登录的, 从1.5版本后不能打开网页授权了
                bundle.putString("sdkv", "1.4.0");
            }
            return bundle;
        }
    }

以下方案是基于2.9.4lite:

    /**
     * 解决网页授权问题
     *
     * @return true: 成功; false: 失败
     */
    private boolean fixWebAuth(Context context, Tencent tencent) {
        if (AppUtils.isAppInstalled(context.getApplicationContext(), "com.tencent.mobileqq")) {
            return true;
        }
        if (tencent == null) {
            return false;
        }
        boolean ok = false;
        try {
            Field aField = tencent.getClass().getDeclaredField("mQQAuth");
            aField.setAccessible(true);
            Object cVal = aField.get(tencent);
            Field authAgentField = cVal.getClass().getDeclaredField("a");
            authAgentField.setAccessible(true);
            authAgentField.set(cVal, new FixWebAuthAgent(tencent.getQQToken()));
            ok = true;
        } catch (Throwable ignore) {
        }
        return ok;
    }

    /**
     * 解决网页授权问题的AuthAgent
     */
    private static class FixWebAuthAgent extends AuthAgent {

        FixWebAuthAgent(QQToken qqToken) {
            super(qqToken);
        }

        @Override
        protected Bundle composeCGIParams() {
            Bundle bundle = super.composeCGIParams();
            if (bundle != null) {
                // 主要原因在这, 腾讯的server估计是判断这个版本号来进行限制登录的, 从1.5版本后不能打开网页授权了
                bundle.putString("sdkv", "1.4.0");
            }
            return bundle;
        }
    }

其他的sdk版本请自测。

参考:

  • 2
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

注意: 不需要很多的类库 全部下来只有三个文件 。一个类库和两个前台页面,你将类库放到AppCode下面。然后将账号绑定那一块注释掉就行了,或者将账号绑定部分换成你自己系统的。就可以了。程序报错可能是因为我在绑定账号那里用到了别的类,你注释掉就行了 ------------------------------------------------------------ 经过两天的努力 已经成功将QQ登录集成到了 城记网 上。感谢腾讯提供的帮助文档,和关键时刻给的技术支持。我的网站是asp.net写的,有需要的网友可以联系我。 呵呵。(尽管是垃圾站,只要你愿意,又有什么关系呢?) QQ Oauth 只提供PHP的接入demo ,针对 ASP.net 的只有一个网友开发的SDK包,下载地址还老打不开,后来我从CSDN上下载了一个,看了以后感觉太复杂了,我个人感觉做这么个小事情不需要搞个SDK出来,不如自己按帮助文档去写,这样自己写的方法灵活性就高一些,于是就按文档学习开发。其实文档写得很清晰,耐心一看就明白了。 不讲太多的郁闷的过程了,直接说解决办法。 办这个事情主要要知道下面几个事情。 两个重点(如下): 第一个重点:请求Token的步骤, 1:请求未授权的临时token。请求成功以后会转到QQ登录页面。 2:请求已授权的临时token。登陆成功以后获得。 3:请求已授权的Access token。 第二个重点:签名的算法。 签名的值计算有一个指定的规则,请参考腾讯开放社区帮助文档,这是最 好的资料。 注意点: 没有申请APPID和APPKEY的先去申请。 传递的每一参数都要URLENcode,注意是每一个,包括动态生成的签名。    参数之间是有顺序的,是升序排列的,无论有多少个,都要排序。    各个步骤之间是有关联的,下一步的提交往往需要上一步的返回参数。 我采取的文档结构: 总共三个文件 ,非常简单。 一个放在APPcode下面的类。用来发送请求和接待参数。 两个前台页面,主要是对类的调用。 下面把类的代码完全贴出,你知要一看见类,就知道怎么写前台页面了,很简单
简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除,从账户中取出amt,如果amt>账户余额抛出异常,一个实体Bean可以表示不同的数据实例,我们应该通过主键来判断删除哪个数据实例…… ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现 ,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程接口的引用,用远程接口的引用访问EJB。 EJB中JNDI的使用源码例子 1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上直接地使用它,但是它的主要作用是供程序使用的。本规范尝试满足大型主机、微型主机、个人工作站、和TACs 的不同需求。例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密   Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。   设定字符串为“张三,你好,我是李四”   产生张三的密钥对(keyPairZhang)   张三生成公钥(publicKeyZhang)并发送给李四,这里发送的是公钥的数组字节   通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 同上 java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java源码,算法相关,密钥   Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从文件中得到公钥编码的字节数组、如何从字节数组解码公钥。 Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输   Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值