当前位置: 首页 > 知识库问答 >
问题:

在不登录Google帐户的情况下验证您的客户端到云endpoint

堵乐
2023-03-14

这样做的原因是我想要保护我的API或者“锁定”它只对我指定的客户机。有时我会有一个没有用户登录的应用程序。我不想纠缠我的用户现在登录只是为了我的API是安全的。或者其他时候,我只想像在一个网站上那样管理自己的用户,而不使用Google+、Facebook,或者其他什么登录认证。

首先,让我介绍一下如何使用文档中指定的Google Accounts登录名,通过云endpointAPI验证Android应用程序。之后,我将向你展示我的发现和一个解决方案的潜在领域,我需要帮助。

(1)指定被授权向API后端发出请求的应用程序的客户端ID(ClientID);(2)向所有要受授权保护的公开方法添加一个用户参数。

public class Constants {
      public static final String WEB_CLIENT_ID = "1-web-apps.apps.googleusercontent.com";
      public static final String ANDROID_CLIENT_ID = "2-android-apps.googleusercontent.com";
      public static final String IOS_CLIENT_ID = "3-ios-apps.googleusercontent.com";
      public static final String ANDROID_AUDIENCE = WEB_CLIENT_ID;

      public static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email";
    }


import com.google.api.server.spi.auth.common.User; //import for the User object

    @Api(name = "myApi", version = "v1",
         namespace = @ApiNamespace(ownerDomain = "${endpointOwnerDomain}",
         ownerName = "${endpointOwnerDomain}",
         packagePath="${endpointPackagePath}"),
         scopes = {Constants.EMAIL_SCOPE}, 
         clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID,
                      Constants.IOS_CLIENT_ID,
                      Constants.API_EXPLORER_CLIENT_ID},
                      audiences = {Constants.ANDROID_AUDIENCE})

    public class MyEndpoint {

        /** A simple endpoint method that takes a name and says Hi back */
        @ApiMethod(name = "sayHi")
        public MyBean sayHi(@Named("name") String name, User user) throws UnauthorizedException {
            if (user == null) throw new UnauthorizedException("User is Not Valid");
            MyBean response = new MyBean();
            response.setData("Hi, " + name);

            return response;
        }

    } 

(3)在Android中,调用Asynctask中的API方法,确保在Builder中传入Credential变量:

class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
        private static MyApi myApiService = null;
        private Context context;

        @Override
        protected String doInBackground(Pair<Context, String>... params) {
            credential = GoogleAccountCredential.usingAudience(this,
            "server:client_id:1-web-app.apps.googleusercontent.com");
            credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
            if(myApiService == null) {  // Only do this once
                MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
                        new AndroidJsonFactory(), credential)
                    // options for running against local devappserver
                    // - 10.0.2.2 is localhost's IP address in Android emulator
                    // - turn off compression when running against local devappserver
                    .setRootUrl("http://<your-app-engine-project-id-here>/_ah/api/")
                    .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                        @Override
                        public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
                            abstractGoogleClientRequest.setDisableGZipContent(true);
                        }
                    });
                    // end options for devappserver

                myApiService = builder.build();
            }

            context = params[0].first;
            String name = params[0].second;

            try {
                return myApiService.sayHi(name).execute().getData();
            } catch (IOException e) {
                return e.getMessage();
            }
        }

        @Override
        protected void onPostExecute(String result) {
            Toast.makeText(context, result, Toast.LENGTH_LONG).show();
        }
    }

正在发生的情况是,在Android应用程序中,首先显示Google account picker,将Google account电子邮件存储在您的共享首选项中,然后将其设置为GoogleAccountCredential对象的一部分(在此提供更多信息)。

Google App Engine服务器接收您的请求并进行检查。如果Android客户机是您在@API符号中指定的客户机之一,那么服务器将把com.google.API.server.spi.auth.common.user对象注入到您的API方法中。现在您有责任检查user对象是否为null或不在API方法中。如果user对象为null,则应在方法中引发异常以阻止其运行。如果不执行此检查,您的API方法将执行(如果试图限制对它的访问,则为no-no)。

您可以访问Google Developers Console获得android_client_id。在这里,您提供了Android应用程序的包名和SHA1,它为您生成了一个Android客户端id,供您在@api注释中使用(或者将其放在一个类constants中,就像上面为可用性指定的那样)。

我对上述所有内容做了一些广泛的测试,以下是我的发现:

如果您在@API注释中指定了伪造的或无效的Android clientId,则在API方法中,user对象将为null。如果您正在检查If(user==null)是否抛出新的UnauthorizedException(“user is Not valid”);,那么您的API方法将不会运行。

这是令人惊讶的,因为云endpoint中似乎正在进行一些幕后验证,以检查Android ClientId是否有效。如果它无效,它将不会返回user对象--即使最终用户登录到他们的Google帐户并且GoogleAccountCredential有效。

我的问题是,有人知道我如何在我的云endpoint方法中检查这种类型的ClientId验证吗?例如,该信息可以在HttpHeader中传递吗?

云endpoint中注入的另一种类型是javax.html" target="_blank">servlet.http.HttpServletRequest。您可以在您的API方法中获得如下所示的请求:

@ApiMethod(name = "sayHi")
            public MyBean sayHi(@Named("name") String name, HttpServletRequest req) throws UnauthorizedException {

                String Auth = req.getHeader("Authorization");//always null based on my tests
                MyBean response = new MyBean();
                response.setData("Hi, " + name);

                return response;
            }

        }  

这样,您就可以将API锁定到Android应用程序(可能还有其他客户端),而不必纠缠最终用户登录(或者只需创建您自己的简单用户名+密码登录)。

要使所有这些工作正常,您必须在Builder的第三个参数中传入null,如下所示:

myapi.builder builder=new myapi.builder(AndroidHttp.NewCompatibleTransport(),new AndroidJsonFactory(),null)

然后在API方法中提取调用是否来自经过身份验证的客户机,并抛出异常或运行您想要的任何代码。

我知道这是可能的,因为当在Builder中使用GoogleAccountCredential时,云endpoint知道调用是否来自经过身份验证的客户端,然后将其User对象注入API方法,或者是否基于此。

这些信息可能会在标题或正文中吗?如果是这样,我如何将它取出以便稍后检查它是否存在于我的API方法中?

注意:我看了其他关于这个话题的帖子。它们提供了传递您自己的身份验证令牌的方法--这很好--但如果有人对.apk进行反编译,它仍然不安全。我认为如果我的假设有效,您将能够将您的云endpointAPI锁定到客户机,而无需任何登录。

Google Cloud终结点的自定义身份验证(而不是OAuth2)

将我的“应用程序”身份验证给谷歌云endpoint而不是“用户”

(皱着眉头的脸)--不过,也许还是有可能的?

暂时还没有答案

 类似资料:
  • 在主机上安装harbor。使用普通HTTP协议。 IP为。 我可以从harbor服务器本身登录它: 并可以从浏览器访问它: https://github.com/vmware/harbor/blob/master/docs/installation_guide.md 重要提示:Harbor的默认安装使用HTTP--因此,您需要将选项--insecure-registry添加到客户端的Docker守

  • 我正在开发一个在JBOSS Wildfly下运行的JSF2应用程序,它利用了Java的JAAS安全机制。 一切都按预期工作,我可以使用 request.login(用户名,密码)机制登录。 我还需要授权设备(我已使用cookie实现)作为登录过程的一部分。我试图实施的过程如下: 验证用户名和密码(但不登录) 检查设备授权并重定向到授权过程页面(如果尚未授权)。 登录(如果授权成功) 除非用户被授权

  • 我正在处理一个使用PHP的项目,需要使用PHP客户端库实现Google CloudAPI,但身份验证似乎对我不起作用。我已经创建了一个服务帐户并授予了项目所有者权限,我不想通过使用GOOGLE_DEFAULT_CREDENTIALS环境变量进行身份验证,我想使用服务帐户身份验证。 致命错误:未捕获异常“Google\Cloud\Core\exception\ServiceException”,消息

  • 从命令行,我可以像这样登录mysql: (仅供参考,不能使用本地主机,必须使用IP)我可以得到:http://myhost.com/phpmyadmin/ 但我无法使用myuser帐户登录 - 收到重复的登录提示并最终“拒绝访问”。 所以我尝试编辑:/var/lib/phpmyadmin/config.inc.php添加了: < Li > $ CFG[' Servers '][1][' host

  • 我有一个场景,我通过使用firebase身份验证通过匿名登录,并从匿名登录帐户,我已经从事件列表中添加了事件作为收藏夹项目,现在我想使用Google或Facebook登录,以便我最喜欢的项目永远不会丢失,每当我登录收藏夹项目必须从该登录帐户获得。 我正在使用上述场景Firebase链接。但问题是,firebase链接只对一个匿名帐户有效一次,如果我再次匿名登录并添加最喜欢的事件,现在我使用以前的方

  • 因此,为了实现这个逻辑,我认为我需要在客户端验证JWT令牌。Q1,这是一个明智的做法吗。 Q2,我正在使用的库似乎需要一个公钥才能使用它的函数。我似乎没有公钥,只有一个秘密,这是我刚刚编造的,所以它不是用一对生成的。我的公钥从何而来,或者是否有另一种方法来验证我的令牌而不使用此方法? 这一切似乎应该是显而易见的,我错过了一些东西,所以很抱歉,如果这是一个愚蠢的问题,但我似乎找不到答案?