繁体   English   中英

如何限制Google App Engine端点API只能访问我的Android应用程序?

[英]How do I restrict Google App Engine Endpoints API access to only my Android applications?

我是一名Android开发人员,为我的应用构建了我的第一个Google App Engine(java)后端。 除了我的应用程序之外,我不希望任何其他人访问此API。 (我计划在我的Android应用程序中使用App引擎验证InApp购买)。 我的数据与用户无关,因此我不希望用户即使使用他们的Google帐户(在网络或Android设备上)登录也能访问我的API。

我按照“在API后端中指定授权客户端”( https://developers.google.com/appengine/docs/java/endpoints/auth )中提到的步骤进行操作,例如生成客户端ID并将其添加到@Api(clientIds和观众)除了“添加用户参数” - 因为我不需要用户身份验证。

然后我部署了App引擎,我仍然可以通过API资源管理器访问API( https://your_app_id.appspot.com/_ah/api/explorer )(我还没有添加API_EXPLORER客户端ID)

我在添加客户端ID之前使用使用端点库构建的APK进行了测试,并且仍然可以访问API。

  • 是否必须向所有端点API添加“用户参数”? 实现我的目的(限制API到我的Android应用程序)。

  • 我可以从Android客户端传递null作为userAccount名称并忽略服务器上的用户参数值(因为它将为null)? 这是否确保API只能从我的Android应用程序访问(因为客户端ID是为我的包名和APK的SHA1生成的?)

  • 我应该为此目的使用类似服务帐户的东西吗?

文档说,对于Android,必须添加Android和Web客户端ID,并且受众必须与Web客户端ID相同。 这是否可以访问任何其他Web客户端? 我可以跳过提及Web客户端ID并仍然达到我的目的吗?

感谢您的时间和帮助。

......随着我的进一步调查而更新......

我做了以下事情:

  • 在后端的API中添加了User参数 - 但没有检查空值。 无需传递任何凭据即可访问API(来自Android调试APK和API资源管理器)

  • 然后,我试过了

    mCredential = GoogleAccountCredential.usingAudience(this,“server:client_id:”+ WEB_CLIENT_ID); mCredential.setSelectedAccountName(NULL);

并将此凭据传递给API构建器(如其他一些帖子中所建议的)导致致命异常。 所以,我们不能传递null帐户名。

  • 我可以在没有OAuth的情况下使用API​​资源管理器调用API。 但是当我启用OAuth时,它提示错误,说不允许此客户端ID! (我还没有在client_ids {}中添加com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID)

  • 然后我添加了代码,如果用户为null,则在后端抛出OAuthRequestException。 这导致API资源管理器在没有OAuth的情况下收到错误。 将API_EXPLORER_CLIENT_ID添加到client_ids后,它可以启用OAuth

  • 添加了从我的Android应用程序传递有效用户帐户名(电子邮件)的代码。 然后,我只能使用我的发布APK访问API。 即使是调试APK也有例外! - 这是我的预期。所以,我认为没有其他Android应用程序能够访问此API。

因此,不检查后端API上的null用户是个坏主意(如其他帖子所示)。 它没有提到任何client_ids而没有User param。

我现在唯一的问题是:如果有人可以从APK中找出WEB_CLIENT_ID,他们是否可以使用它来构建一个Web客户端来访问我的API(我没有在代码中的任何地方提到过客户端秘密。所以我认为这是不可能的)。


我确实搜索了Google群组和Stackoverflow,但目前尚不清楚。

我有类似的问题,不是在Android和App Engine之间,而是在单独的服务器和App Engine之间。 我处理它的方法是将签名哈希字段作为参数添加到每个API调用。 如果请求有不正确的签名,则会被拒绝。

例如,假设您的API端点是example.com/api/do_thing?param1=foo 我将散列整个url以及一个密钥,然后将哈希的结果附加到请求: example.com/api/do_thing?param1=foo&hash=[some long hex value] hash=[ example.com/api/do_thing?param1=foo&hash=[some long hex value]

然后,在服务器端,我首先从url请求中删除哈希,然后对剩余的所有内容运行哈希。 最后,检查计算的散列是否与随请求一起发送的散列匹配,如果不匹配,则可以拒绝该请求。

但是,您的密钥仍然保密,这一点非常重要。 您必须在Android上小心这一点,因为有人可能会尝试反编译您的APK。

面对同样的问题比你! 在没有Google用户帐户的情况下验证Android端点是不可能的!

所以这是我解决这个问题的方法,没有任何用户交互(也许不是正确但有效,你有强大的身份验证(SHA1 + Google帐户)):

这是我的安卓代码

获取并构建有效凭据

  //Get all accounts from my Android Phone
         String validGoogleAccount = null;
         Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
         Account[] accounts = AccountManager.get(context).getAccounts();
         for (Account account : accounts) {
             if (emailPattern.matcher(account.name).matches()) {
                 //Just store mail if countain gmail.com
                 if (account.name.toString().contains("gmail.com")&&account.type.toString().contains("com.google")){
                     validGoogleAccount=account.name.toString();
                 }

             }
         }

        //Build Credential with valid google account
        GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this,"server:client_id:301991144702-5qkqclsogd0b4fnkhrja7hppshrvp4kh.apps.googleusercontent.com");
        credential.setSelectedAccountName(validGoogleAccount);

使用此凭据进行安全呼叫

Campagneendpoint.Builder endpointBuilder = new Campagneendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), credential);

这是我的API后缀代码: API注释

@Api(
        scopes=CONSTANTES.EMAIL_SCOPE,
        clientIds = {CONSTANTES.ANDROID_CLIENT_ID, 
                     CONSTANTES.WEB_CLIENT_ID,
                     com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
        audiences = {CONSTANTES.ANDROID_AUDIENCE},      
        name = "campagneendpoint",
        version = "v1"
     )

方法代码:

public Collection<Campagne> getCampagnes(@Named("NumPortable")String NumPortable, User user) throws  UnauthorizedException {
        if (user == null) throw new UnauthorizedException("User is Not Valid");

      return CampagneCRUD.getInstance().findCampagne(NumPortable);
     }

目前,它只适用于Android(我不知道我们将如何做IOS ..)..

希望它会对你有所帮助!

Google提供了针对AndroidwebiOS执行此操作的方法。步骤包括:

  1. 为要允许向API发出请求的应用指定客户端ID
  2. 将User参数添加到要受授权保护的所有公开方法。
  3. 为任何Android客户端再次生成客户端库
  4. 重新部署后端API。
  5. 将重新生成的jar文件更新为Android客户端的Android项目。

这些步骤在Google的Using Auth with Endpoints和此博客都有详细的详细说明

面对同样的问题,这是我研究的结果:

  • 在Google控制台中添加了带有SHA1指纹的Android cliend id
  • 在API注释中使用它

但是:

  • 如果我没有向方法添加用户参数:检查有关Android应用程序客户端ID不起作用

  • 如果我添加USER参数但不要求用户选择其谷歌帐户来创建凭证...也不起作用...

结论:似乎必须连接用户帐户以检查要执行的应用程序客户端ID ...我真的不明白为什么因为2个进程之间不存在链接

访问此站点

选择您的项目,转到凭证部分

创建一个新的api密钥

创建一个新的Android密钥

单击“编辑允许的Android应用程序”并输入您的SHA1密钥; 你的android包名

如果这解决了问题,请告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM