API 是移动应用程序的后端。我不需要用户身份验证。我只需要一种方法来保护对这个 API 的访问。目前,我的后端已暴露。
文档似乎只讲用户认证和授权,这不是我这里需要的。我只需要确保只有我的移动应用程序可以与这个后端对话,而没有其他人可以对话。
API 是移动应用程序的后端。我不需要用户身份验证。我只需要一种方法来保护对这个 API 的访问。目前,我的后端已暴露。
文档似乎只讲用户认证和授权,这不是我这里需要的。我只需要确保只有我的移动应用程序可以与这个后端对话,而没有其他人可以对话。
是的,您可以这样做:使用身份验证来保护您的端点,而无需进行用户身份验证。
我发现这种方法没有很好的文档记录,我自己也没有真正做过,但我打算这样做,所以当我看到一些 IO13 视频中讨论它时我注意到了(我认为那是我看到了):
以下是我对所涉及内容的理解:
您将这些客户端 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 );
这个客户端代码只是我最好的猜测——抱歉。如果其他人有关于客户端代码应该是什么样子的参考,那么我也会感兴趣。
该文档仅供客户使用。我需要的是有关如何在服务器端提供服务帐户功能的文档。
这可能意味着几件不同的事情,但我想谈谈我认为这个问题要问的问题。如果您只希望您的服务帐户访问您的服务,那么您只需将服务帐户的 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
很抱歉,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!')
希望这能让你走上正确的轨道