安卓接入Twitter三方登录

接twitter登录进行验证的时候需要科学上网,这个前提应该都明白,不多说了。

按照官方给的案例,接twitter登录用的是twitter的sdk进行验证,我们以前也用这个方式跑通。

官方文档如下:

https://github.com/twitter-archive/twitter-kit-android/wiki/Log-In-with-Twitter

https://github.com/twitter-archive/twitter-kit-android

参考官方文档后,实现此需求难度不大。使用这种方式进行登录的博文也比较多,可以参考这篇:

https://www.jianshu.com/p/a31f05fa30af

不过最近在给一个新app接twitter登录时使用一样的接法,却出现问题了,一直报证书问题,让我一度以为是后台配置有什么问题。报错的内容大概是说twitter sdk的证书哈希与服务器返回的证书哈希值对不上。

后面把新app后台配置的key和secret填到旧app的登录代码里面发现没什么问题,可以正常登录;旧app的key和secret填到新app的登录代码同样报错证书问题,并且就算随便填什么东西都一样报证书问题,于是怀疑后台配置没什么问题,AI给出的回答是twitter sdk版本太老了,并且其sdk内部是写死了证书哈希的,如果是后台新创建的app,其证书是服务器新生成的,就会和sdk对不上导致报错,不过网上也找不到什么确切回答,只能暂且认为是这样,如果各位大佬知道可以回复一下。

既然有这种问题,只能另外找方法了,这里提供两个方法,可以参考一下。(都只能网页授权,不能拉起app)

目录

[1.通过firebase代替twitter sdk进行验证和授权](#1.通过firebase代替twitter sdk进行验证和授权)

[2.通过X API方式进行验证和授权(手动进行OAuth认证)](#2.通过X API方式进行验证和授权(手动进行OAuth认证))

如果不想看流程,可以直接看代码

如何使用twitter-api-java-sdk简化twitter三方登录流程


1.通过firebase代替twitter sdk进行验证和授权

这种方法优点是同样有文档可以参考,而且接入也不麻烦,一般会接twitter登录的app都是上谷歌的,firebase也都配置过,而且firebase可以一起集成google登录、facebook登录、twitter登录、apple登录,正好都统一了,不用接这么多sdk。

问题也是有的,首先和twitter登录不一样,使用firebase代替twitter sdk进行授权登录,返回的用户唯一标识是firebase自己生成的uid,而twitter sdk返回的唯一标识是authtoken,格式上不一样,如果是一个新app且没有ios端或者其它端,那这种方式可能适合你。如果是升级或者有多端,可能会出现什么问题呢,首先第一个是由于同个用户的唯一标识不一样了,导致账号会重新创建;另外ios没有firebase可以接入,就会导致两端对于同个twitter用户,拿到的唯一标识格式不一样,进而双端账号不互通。

文档参考:https://firebase.google.cn/docs/auth/android/twitter-login?hl=zh-cn#java_6

2.通过X API方式进行验证和授权(手动进行OAuth认证)

前面的使用Twitter sdk或者firebase的方式其实都是帮我们做了OAuth认证过程,我们也可以手动去处理这个过程,可以参考文档里认证部分的内容。文档链接:https://docs.x.com/fundamentals/authentication/overview 这里面各项内容都看一下

如果不想看流程,可以直接看代码

先看看概述,这里面有说到几种身份验证方法,并且在注意里面特意提到要代表其它用户发请求需要使用3-legged Oauth生成令牌,并使用OAuth 1.0a或者OAuth2.0传递,那我们后面使用的身份验证就是OAuth 1.0a或者是PKCE的OAuth 2.0

之后点到指南的使用X登录,要求我们知道如何使用OAuth 1.0a,那我们要先看看1.0a怎么用

点到OAuth 1.0a的授权请求页面看看,文档说需要修改http请求以向X API发送授权请求,host是api.x.com 这个后续会用到,继续往下看

文档说任何http库都可以发出以上http请求,但是上面的例子无效,因为有很多信息不知道,即需要我们传参,总共有7个东西要传,再往下是解释这些参数是什么,可能一开始看着很难搞,不过后面用了库之后都会直接帮我们处理好,需要做的事情很简单。

看完授权请求后回到之前的使用X登录,根据文档可知需要3个步骤完成登录

第一步请求令牌,调用oauth/request_token接口,使用post方式,需要传参oauth_callback,其它参数在签名时添加,oauth_callback需要在twitter的后台callbacks里面配置,配置内容应该只要符合scheme://host就行,文档给的例子是http://localhost/sign-in-with-twitter/,我之前配的是myappname://twitter-callback也没问题,只要对的上就行

第二步重定向用户,调用oauth/authenticate接口,使用get方法,根据示例url应该很容易明白,不过这里有个坑,可以点到OAuth 1.0a的用户访问令牌看看。

另外响应的callback_url将收到包含oauth_token和oauth_verifier参数的请求。应用程序应验证令牌是否与步骤 1 中收到的请求令牌匹配。这个验证令牌不是必须

使用3-legged OAuth需要换oauth/authorize接口,并且每一次点击登录都需要重新授权,哪怕之前授权过,实际表现是后续对接成功后,每次点击登录都会让你授权,不像sdk登录那样只第一次需要进行授权。所以之前第二步最终请求的应该是https://api.x.com/oauth/authenticate再拼接参数。

第三步将请求令牌转换为访问令牌,需请求接口oauth/access_token,使用post方法,需要将第二步拿到的oauth_verifier作为参数传给服务器,响应中的oauth_token字段就是用户的唯一标识,可以传给自己后端服务器去创建账号了。(注意第一步响应也会出现oauth_token字段,第二步响应同样会返回的callback_url中也包含这个字段,正常情况下这两个oauth_token一样,同时和第三步拿到的oauth_token不一样,第三步这个才是用户唯一标识)

如何使用twitter-api-java-sdk简化twitter三方登录流程

了解过程之后,我们可以使用一些库简化这个数据交互过程,例如我是使用了twitter的api sdk,地址如下:https://github.com/xdevplatform/twitter-api-java-sdk

不过进入github项目发现给的案例是OAuth 2.0 only-app 的验证方式,没有OAuth 1.0a和OAuth 2.0 PKCE的方式,only-app这种方式无法进行三方登录验证和授权,所以我只能结合ai写了一个OAuth 1.0a的授权登录,OAuth 2.0 PKCE的方式你需要去看OAuth 2.0 PKCE的授权流程,然后再摸索twitter-api-java-sdk怎么用,我懒得搞了,反正官方流程用的1.0a,实际上也可以跑通,就用了1.0a

尝试1.0a之后发现只用到twitter-api-java-sdk里面一小部分内容,一个OAuth认证的库,可以直接引入,不用将twitter-api-java-sdk整个引入

Groovy 复制代码
implementation 'com.github.scribejava:scribejava-apis:8.3.3' 
或者  
implementation "com.twitter:twitter-api-java-sdk:2.0.3"

对进行三方登录的Activity配置intent-filter以接收twitter后台配置的callback,同时记得把activity进行exported,我后台配置的callback是myappname://twitter-callback,看完你应该也知道怎么填了,如果你使用twitter官方案例callback,http://localhost/sign-in-with-twitter/,那scheme应该是http,host应该是localhost/sign-in-with-twitter

接下来就是实际登录代码了

java 复制代码
    //twitter登陆使用
    private OAuth10aService mTwitterService;  //为我们执行请求的类
    private OAuth1RequestToken mTwitterRequestToken;  //第一步拿到的requestToken
    public static final String TWITTER_API_KAY = "ababababba";//OAuth 1.0
    public static final String TWITTER_API_KAY_SECRET = "ababbabab";//OAuth 1.0
    public static final String TWITTER_CALLBACK_URL = "myappname://twitter-callback";        
            //后台定义的callback,需要和LoginActivity的intent-filter里面scheme、host对上


private void initTwitterLogin() {
    // 创建 OAuth1.0a Service(ScribeJava)
    mTwitterService = new ServiceBuilder(TWITTER_API_KAY)
          .apiSecret(TWITTER_API_KAY_SECRET)
          .callback(TWITTER_CALLBACK_URL)
          .build(new DefaultApi10a() {
               @Override
               public String getRequestTokenEndpoint() {
                    return "https://api.x.com/oauth/request_token"; 
               }

               @Override
               public String getAccessTokenEndpoint() {
                    return "https://api.x.com/oauth/access_token";
               }

               @Override
               protected String getAuthorizationBaseUrl() {
                    return "https://api.x.com/oauth/authorize";
               }
            });
    binding.ivTwitterLogin.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
                // 显示加载对话框
                //showLoadingDialog(false, "", null);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                       try {
                           // 第一步获取request token
                           mTwitterRequestToken = mTwitterService.getRequestToken();
                           // 获取重定向URL
                           String authorizationUrl = 
                              mTwitterService.getAuthorizationUrl(mTwitterRequestToken);
                           // 在主线程中启动浏览器
                           runOnUiThread(new Runnable() {
                              @Override
                              public void run() {
                                   //dismissLoadingDialog();
                                   // 启动浏览器进行授权
                                   Intent intent = new Intent(Intent.ACTION_VIEW, 
                                                        Uri.parse(authorizationUrl));
                                   startActivity(intent);
                               }
                            });
                        } catch (Exception e) {
                            Log.e(TAG, "Twitter OAuth error: " + e.getMessage());
                        }
                    }
             }).start();

         }
    });
}


@Override
protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        LogUtil.d(TAG, "onNewIntent intent= " + intent);
        //第二步浏览器回调的callback_url
        Uri uri = intent.getData();
        if (uri != null && GlobalDefines.TWITTER_CALLBACK_URL.equals(
                            uri.getScheme() + "://" + uri.getHost())) {
            String verifier = uri.getQueryParameter(OAuthConstants.VERIFIER);

//          可以检查此token与第一步的是否一致
//          String token = uri.getQueryParameter(OAuthConstants.TOKEN);
       
            if (!TextUtils.isEmpty(verifier)) {
                exchangeAccessToken(verifier);
            } else {
                Toast.makeText(this, "Twitter login cancelled", 
                                    Toast.LENGTH_SHORT).show();
            }
        }
}
private void exchangeAccessToken(String verifier) {
//        showLoadingDialog(false, "", null);
        new Thread(() -> {
            try {
                //第三步获取access_token
                OAuth1AccessToken accessToken = 
                     mTwitterService.getAccessToken(mTwitterRequestToken, verifier);
                //第三步拿到的oauth_token才作为用户唯一标识
                String oauth_token = accessToken.getParameter(OAuthConstants.TOKEN); 
                LogUtil.d(TAG, " oauth_token= " + oauth_token);

                runOnUiThread(() -> {
//                    dismissLoadingDialog();
//                    authorizationLogin(oauth_token); //你自己的三方登录逻辑
                });
            } catch (Exception e) {
                Log.e(TAG, "exchangeAccessToken error= " + e);
                runOnUiThread(() -> {
//                    dismissLoadingDialog();
                });
            }
        }).start();
}

和谷歌比起来,twitter这个破东西真的不好搞,文档也没给什么案例抄,报错也很难找到答案,搞了好久才搞定,总之就是好想吐槽。

相关推荐
泡泡以安5 小时前
【Android逆向工程】第3章:Java 字节码与 Smali 语法基础
android·java·安卓逆向
毕设源码-朱学姐10 小时前
【开题答辩全过程】以 工厂能耗分析平台的设计与实现为例,包含答辩的问题和答案
java·vue.js
一笑的小酒馆11 小时前
Android launcher3实现简单的负一屏功能
android
xuyin120411 小时前
【Android】Flow基础知识和使用
android
Spring AI学习12 小时前
Spring AI深度解析(9/50):可观测性与监控体系实战
java·人工智能·spring
李新_13 小时前
基于Markwon封装Markdown组件
android·aigc·markdown
java1234_小锋13 小时前
Spring IoC的实现机制是什么?
java·后端·spring
xqqxqxxq13 小时前
背单词软件技术笔记(V2.0扩展版)
java·笔记·python
消失的旧时光-194313 小时前
深入理解 Java 线程池(二):ThreadPoolExecutor 执行流程 + 运行状态 + ctl 原理全解析
java·开发语言
哈哈老师啊13 小时前
Springboot学生综合测评系统hxtne(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·数据库·spring boot