21

API 是移动应用程序的后端。我不需要用户身份验证。我只需要一种方法来保护对这个 API 的访问。目前,我的后端已暴露。

文档似乎只讲用户认证和授权,这不是我这里需要的。我只需要确保只有我的移动应用程序可以与这个后端对话,而没有其他人可以对话。

4

3 回答 3

4

是的,您可以这样做:使用身份验证来保护您的端点,而无需进行用户身份验证。

我发现这种方法没有很好的文档记录,我自己也没有真正做过,但我打算这样做,所以当我看到一些 IO13 视频中讨论它时我注意到了(我认为那是我看到了):

以下是我对所涉及内容的理解:

  • 创建一个 Google API 项目(尽管这并不真正涉及他们的 API,除了身份验证本身)。
  • 创建 OATH 客户端 ID,通过其包名称和您将用来签署应用程序的证书的 SHA1 指纹与您的应用程序绑定。

您将这些客户端 ID 添加到您的端点的可接受 ID 列表中。您将 User 参数添加到您的端点,但由于未指定用户,它将为 null。

@ApiMethod(
   name = "sendInfo",
   clientIds = { Config.WEB_CLIENT_ID, Config.MY_APP_CLIENT_ID, Config.MY_DEBUG_CLIENT_ID },
   audiences = { Config.WEB_CLIENT_ID } 
   // Yes, you specify a 'web' ID even if this isn't a Web client.
)
public void sendInfo(User user, Info greeting) {

这里有一些关于上述内容的不错的文档: https ://developers.google.com/appengine/docs/java/endpoints/auth

您的客户端应用程序将在制定端点服务调用时指定这些客户端 ID。所有 OATH 详细信息都将在您的客户端设备上得到后台处理,以便您的客户端 ID 被转换为身份验证令牌。

HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience( ctx, Config.WEB_CLIENT_ID );
//credential.setSelectedAccountName( user );  // not specify a user
Myendpoint.Builder builder = new Myendpoint.Builder( transport, jsonFactory, credential );  

这个客户端代码只是我最好的猜测——抱歉。如果其他人有关于客户端代码应该是什么样子的参考,那么我也会感兴趣。

于 2013-06-03T16:39:51.100 回答
2

该文档仅供客户使用。我需要的是有关如何在服务器端提供服务帐户功能的文档。

这可能意味着几件不同的事情,但我想谈谈我认为这个问题要问的问题。如果您只希望您的服务帐户访问您的服务,那么您只需将服务帐户的 clientId 添加到您的 @Api/@ApiMethod 注释中,构建一个 GoogleCredential,然后像往常一样调用您的服务。具体来说...

在 google 开发者控制台中,创建一个新的服务帐户。这将创建一个自动下载的 .p12 文件。客户端在您链接到的文档中使用它。 如果您不能保证 .p12 的安全,那么这并不比密码更安全。 我猜这就是 Cloud Endpoints 文档中没有明确说明的原因。

您将谷歌开发者控制台中显示的 CLIENT ID 添加到 @Api 或 @ApiMethod 注释中的 clientIds

import com.google.appengine.api.users.User

@ApiMethod(name = "doIt", scopes = { Constants.EMAIL_SCOPE }, 
     clientIds = { "12345678901-12acg1ez8lf51spfl06lznd1dsasdfj.apps.googleusercontent.com" })
public void doIt(User user){ //by convention, add User parameter to existing params
    // if no client id is passed or the oauth2 token doesn't 
    // match your clientId then user will be null and the dev server 
    // will print a warning message like this:
    // WARNING: getCurrentUser: clientId 1234654321.apps.googleusercontent.com not allowed
    //..
}

您构建客户端的方式与使用不安全版本的方式相同,唯一的区别是您创建了一个 GoogleCredential 对象以传递给您的服务的 MyService.Builder。

HttpTransport httpTransport = new NetHttpTransport(); // or build AndroidHttpClient on Android however you wish
JsonFactory jsonFactory = new JacksonFactory();

// assuming you put the .p12 for your service acccount 
// (from the developer's console) on the classpath; 
// when you deploy you'll have to figure out where you are really
// going to put this and load it in the appropriate manner 
URL url = getClass().class.getResource("/YOURAPP-b12345677654.p12");
File p12file = new File(url.toURI());

GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setTransport(httpTransport);
credentialBuilder.setJsonFactory(jsonFactory);
//NOTE: use service account EMAIL (not client id)
credentialBuilder.setServiceAccountId("12345678901-12acg1ez8lf51spfl06lznd1dsasdfj@developer.gserviceaccount.com");    credentialBuilder.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email"));
credentialBuilder.setServiceAccountPrivateKeyFromP12File(p12file);
GoogleCredential credential = credentialBuilder.build();

现在以与不安全版本相同的方式调用生成的客户端,除了构建器从上面获取我们的谷歌凭据作为最后一个参数

MyService.Builder builder = new MyService.Builder(httpTransport, jsonFactory, credential);
builder.setApplicationName("APP NAME");
builder.setRootUrl("http://localhost:8080/_ah/api");

final MyService service = builder.build();
// invoke service same as unsecured version
于 2014-11-01T20:06:34.813 回答
2

很抱歉,Google 没有为您的问题提供解决方案(这也是我的问题)。您可以使用他们的 API 密钥机制(请参阅https://developers.google.com/console/help/new/#usingkeys),但由于 Google 自己的 API 浏览器提供的这一策略存在一个巨大漏洞(请参阅https:// developer.google.com/apis-explorer/#p/),这是一个测试 API 的出色开发工具,但它公开了所有 Cloud Endpoint API,而不仅仅是 Google 的服务 API。这意味着任何拥有您项目名称的人都可以在闲暇时浏览和调用您的 API,因为 API 浏览器绕过了 API 密钥安全性。我找到了一种解决方法(基于 bossylobster 对这篇文章的出色回应:Simple Access API (Developer Key) with Google Cloud Endpoint (Python)),即在你的客户端API中传递一个不属于消息请求定义的请求字段,然后在你的API服务器中读取。如果您没有找到未记录的字段,则会引发未经授权的异常。这将堵住 API Explorer 创建的漏洞。在 iOS(我用于我的应用程序)中,您向每个请求类(由 Google 的 API 生成器工具创建的那些)添加一个属性,如下所示:

@property (copy) NSString *hiddenProperty;

并将其值设置为您选择的键。在您的服务器代码(在我的情况下为 python)中,如果您没有看到它或它未设置为您的服务器和客户端将同意的值,则检查它的存在和 barf:

mykey,keytype = request.get_unrecognized_field_info('hiddenProperty')
        if mykey != 'my_supersecret_key':
            raise endpoints.UnauthorizedException('No, you dont!')

希望这能让你走上正确的轨道

于 2014-10-01T04:03:56.963 回答