草庐IT

Android Firebase Rest API 身份验证

coder 2023-11-18 原文

我目前正在开发一个使用 Firebase 实时数据库的应用程序,但是我选择不使用 SDK 从数据库中检索数据。原因是我不希望我的代码与 FireBase 如此紧密地联系在一起,因为一旦构建了应用程序,api 本身就会转移到基于自定义 rest 的 api。

我已经按照文档使用 REST 和 Firebase 实现了 api 调用,没有问题 - POST、GET、DELETE 等。

我遇到的问题是,如果我在数据库上启用任何类型的身份验证,根据我需要随请求发送“access_token”的文档,但是我不知道从哪里检索它。 firebaseUser.getToken(true) 返回看起来像 JWT token 的内容,如果我将其作为 “access_token” 发送,则无法识别该 token 。我收到 401 Unauthorized

我还按照说明设置了一个服务帐户,该帐户似乎生成了一个有效的 token ,但它并不能唯一地标识用户。

所以我的问题是任何人都可以指出如何获取所需的访问 token 来标识哪个用户正在访问该 api 的方向吗?我的 Firebase 项目支持的登录选项是 Google、Facebook 和 Twitter。

最佳答案

如果您要从每一种不同的身份验证模式中寻找不同的 token 或 ID,您应该为每一种模式实现不同的 API:

休息API

To retrieve an access token you need to use a service account. Please see the guide for using Google Service Accounts. You can create a service account credential in your Firebase project from the Service Accounts section of the Firebase console.

As an example, one way to generate an appropriate oauth2 token is with the Java google-api-client.

GoogleCredential googleCred = GoogleCredential.fromStream(new FileInputStream("service_account.json"));
GoogleCredential scoped = googleCred.createScoped(
    Arrays.asList(
      "https://www.googleapis.com/auth/firebase.database",
      "https://www.googleapis.com/auth/userinfo.email"
    )
);
scoped.refreshToken();
String token = scoped.getAccessToken();

成功的请求将由 200 OK 表示HTTP 状态代码。响应包含正在检索的数据:

{ "first": "Jack", "last": "Sparrow" }

数据库 REST API 接受 access_token=<TOKEN>在查询字符串或标题上 Authorization: Bearer <TOKEN>使用服务帐户对请求进行身份验证。

以下示例演示了如何将其用于包含用户名的数据库。您将替换 [PROJECT_ID]使用您的 Firebase 项目的标识符。

Facebook

您应该添加 Facebook SDK到您的应用程序并实现 LoginButtonLoginManager项目要求一些信息作为 public_profile 电子邮件。使用 Facebook SDK 很烦人.关于如何添加它的示例代码是这样的:

// Initialize Facebook Login button
mCallbackManager = CallbackManager.Factory.create();
LoginButton loginButton = (LoginButton) findViewById(R.id.button_facebook_login);
loginButton.setReadPermissions("email", "public_profile");
loginButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
    @Override
    public void onSuccess(LoginResult loginResult) {
        Log.d(TAG, "facebook:onSuccess:" + loginResult);
        handleFacebookAccessToken(loginResult.getAccessToken());
    }

    @Override
    public void onCancel() {
        Log.d(TAG, "facebook:onCancel");
        // ...
    }

    @Override
    public void onError(FacebookException error) {
        Log.d(TAG, "facebook:onError", error);
        // ...
    }
});

另外,在 developers console 里面从 Facebook,您应该创建一个帐户,使用您的应用程序包名称配置一个新项目,并为您的应用程序的调试和发布版本添加 SHA key 。完成所有这些事情后,您将成功地从 LoginResult 中检索到一个 token 。使用方法 getAccessToken() 的对象

您可以在 official documentation 中阅读更多相关信息.

谷歌

Google 更容易,因为它已经连接到 Firebase,你应该添加到你的 Gradle google play services并添加 google services JSON文件已配置到您的应用程序。您可以从 Firebase 控制台获取它。

在此之后,您需要配置一个 GoogleSignInOptions使用 JSON 文件中的 id 的项目:

// Configure Google Sign In
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
                .requestEmail()
                .build();

在此之后,您只需要对 GoogleSignInApi 做出 Intent 在你的应用程序中等待 onActivityResult回调:

private void signIn() {
        Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
        startActivityForResult(signInIntent, RC_SIGN_IN);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
            if (result.isSuccess()) {
                // Google Sign In was successful, authenticate with Firebase
                GoogleSignInAccount account = result.getSignInAccount();
                firebaseAuthWithGoogle(account);
            } else {
                // Google Sign In failed, update UI appropriately
                // ...
            }
        }
    }

在此之后,您将能够从 GoogleSignInAccount 项目中检索 token 。请记住为您的应用程序的调试或发布版本配置不同的 SHA key ,否则 Google 登录将在发布版本中停止工作。

您可以在 official Firebase documentation 中阅读更多相关信息

推特

关于推特,我没有和推特打过交道,所以暂时帮不了你,但我建议你查看Twitter developer documentationfirebase Twitter implementation post .

当我在家做一些 poc 检查它是如何工作时,我会尝试编辑它。

关于 Firebase token

另一个需要了解的好点是 Firebase id token ,它在您的应用程序中对于每个用户和连接都是唯一的,允许您检查同一帐户是否正在尝试同时从不同设备登录,或发送 FCM Cloud Messages 在您的应用中使用在线通知。

要检索它,您应该使用 FirebaseInstanceId使用 API 和方法的对象 FirebaseInstanceId.getInstance() .这会在您的用户登录您的应用时为您检索一个 FirebaseInstance 唯一 ID。

您可以使用 idInstance.getToken() 检索他的 token 并随时将其存储在您的应用程序中,以按照您想要的方式检查和管理它。

Firebase documentation about this不是很清楚,所以推荐大家使用下link ,它对我在我的应用程序中实现它有很大帮助。

关于Android Firebase Rest API 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42778348/

有关Android Firebase Rest API 身份验证的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  4. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  5. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

  6. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  7. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  8. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  9. ruby-on-rails - ruby on rails 模型验证中的浮点精度 - 2

    我正在尝试使用正则表达式验证美元金额:^[0-9]+\.[0-9]{2}$这工作正常,但每当用户提交表单并且美元金额以0(零)结尾时,ruby(或rails?)将0砍掉。所以500.00变成500.0,因此正则表达式验证失败。有没有办法让ruby​​/rails保持用户输入的格式,而不管尾随零? 最佳答案 我假设您的美元金额是小数类型。因此,用户在字段中输入的任何值在保存到数据库之前都会从字符串转换为适当的类型。验证适用于已转换为数字类型的值,因此在您的情况下,正则表达式并不是真正合适的验证过滤器。不过,您有几种可能性可以解决这个问

  10. ruby-on-rails - 嵌套模型验证 - 错误不显示 - 2

    关于这个有很多问题,但似乎都没有帮助。是的,我看过thisrailscast.我有一个作者,他有很多书,像这样:作者:classAuthor书:classBook我创建了以下表单以在authors#show中向作者添加一本书:#labelsandbuttons......使用以下authors_controller方法:defshow@author=Author.find(params[:id])@book=@author.books.buildend...以及以下books_controller方法:defcreate@author=Author.find(params[:autho

随机推荐