Google Cloud Endpoints + Firebase Auth:method_info 未设置
Google Cloud Endpoints + Firebase Auth: method_info is not set
所以我是运行Google提供的示例代码:
package com.neat.backend;
/**
* An endpoint class we are exposing
*/
@Api(
name = "myApi",
version = "v1",
namespace = @ApiNamespace(
ownerDomain = "backend.neat.com",
ownerName = "backend.neat.com",
packagePath = ""
),
issuers = {
@ApiIssuer(
name = "firebase",
issuer = "https://securetoken.google.com/" + PROJECT_ID,
jwksUri = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com")
})
public class MyEndpoint {
@ApiMethod(
path = "firebase_user",
httpMethod = ApiMethod.HttpMethod.GET,
authenticators = {EspAuthenticator.class},
issuerAudiences = {@ApiIssuerAudience(name = "firebase", audiences = {PROJECT_ID})}
)
public Email getUserEmailFirebase(User user) throws UnauthorizedException {
if (user == null) {
throw new UnauthorizedException("Invalid credentials");
}
Email response = new Email(user.getEmail());
return response;
}
}
我正在从我的 Android 客户端获取一个 Firebase 令牌,并尝试通过以下方式将其发送到后端:
curl -H "Authorization: Bearer FIREBASE_JWT_TOKEN" \
-X GET \
http://localhost:8080/_ah/api/echo/v1/firebase_user
我在日志中看到的错误如下:
[INFO] java.lang.IllegalStateException: method_info is not set in the request
[INFO] at com.google.api.server.spi.auth.EspAuthenticator.authenticate(EspAuthenticator.java:67)
[INFO] at com.google.api.server.spi.request.Auth.authenticate(Auth.java:100)
[INFO] at com.google.api.server.spi.request.ServletRequestParamReader.getUser(ServletRequestParamReader.java:191)
[INFO] at com.google.api.server.spi.request.ServletRequestParamReader.deserializeParams(ServletRequestParamReader.java:136)
[INFO] at com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader.java:123)
[INFO] at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:350)
[INFO] at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:114)
[INFO] at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:102)
[INFO] at com.google.api.server.spi.dispatcher.PathDispatcher.dispatch(PathDispatcher.java:49)
[INFO] at com.google.api.server.spi.EndpointsServlet.service(EndpointsServlet.java:71)
[INFO] at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
我已经尝试将完全相同的代码部署到 App Engine,并且效果很好。我试过调试 EspAuthenticator,它似乎期望 Servlet 过滤器在请求中注入一些属性。
我花了一些时间和一些调试才意识到应该注入 method_info 的过滤器没有被触发。
我可以通过修改 web.xml 中的映射来修复它,添加以下调度程序标签:
<filter-mapping>
<filter-name>endpoints-api-configuration</filter-name>
<servlet-name>EndpointsServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
我收到了同样的错误消息,最终追踪到在 URL 中使用尾随 /
发出请求,而我的 API 没有指定。尾部斜杠只会导致提供授权令牌的调用出错。
显然 ControlFilter
(因此 GoogleAppEngineControlFilter
)没有将其识别为有效端点,因此没有费心将 method_info
附加到请求中。但后来 EndpointsServlet
认为它 是 有效的,并试图在没有所有需要的信息的情况下进行身份验证!
修复很简单:删除我请求中 URL 的尾部斜线。然而,追查问题并非如此!我知道这不是你的问题,但也许这个答案会对其他人有所帮助。
生成并部署 OpenAPI 配置文件
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
$ mvn appengine:run
@Kevendra 的回答强调,如果 openapi.json
文件缺少对端点 API 方法的引用,则可能会导致此问题。 Firebase 可能会使用它来引用和发现 API 方法。
来自Google打开API概述:
Basic structure of an OpenAPI document:
An OpenAPI document describes
the surface of your REST API, and defines information such as:
The name and description of the API. The individual endpoints (paths)
in the API. How the callers are authenticated.
按照以下步骤重新生成和部署 openapi.json 文件:
生成:
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
mvn clean
- 运行 清理项目的 Maven 目标。 package
- 编译打包
endpoints-framework:openApiDocs
generate OpenAPI documents. This will generate the openapi.json
file at the location: target/openapi-docs/openapi.json
- see generating and deploying an api configuration.
-DskipTests
跳过 运行ning 任何测试,以避免任何测试失败
openapi.json 尚未生成
部署:
(作为预防措施,您可以先验证从以下命令返回的项目 ID,以确保服务不是在错误的项目中创建的 - gcloud config list project
)
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
从其生成的位置部署 openapi.json 文件(在上面的 'generate' 步骤中)。请参阅 Deploying the OpenAPI document
上的 Google 文档
所以我是运行Google提供的示例代码:
package com.neat.backend;
/**
* An endpoint class we are exposing
*/
@Api(
name = "myApi",
version = "v1",
namespace = @ApiNamespace(
ownerDomain = "backend.neat.com",
ownerName = "backend.neat.com",
packagePath = ""
),
issuers = {
@ApiIssuer(
name = "firebase",
issuer = "https://securetoken.google.com/" + PROJECT_ID,
jwksUri = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com")
})
public class MyEndpoint {
@ApiMethod(
path = "firebase_user",
httpMethod = ApiMethod.HttpMethod.GET,
authenticators = {EspAuthenticator.class},
issuerAudiences = {@ApiIssuerAudience(name = "firebase", audiences = {PROJECT_ID})}
)
public Email getUserEmailFirebase(User user) throws UnauthorizedException {
if (user == null) {
throw new UnauthorizedException("Invalid credentials");
}
Email response = new Email(user.getEmail());
return response;
}
}
我正在从我的 Android 客户端获取一个 Firebase 令牌,并尝试通过以下方式将其发送到后端:
curl -H "Authorization: Bearer FIREBASE_JWT_TOKEN" \
-X GET \
http://localhost:8080/_ah/api/echo/v1/firebase_user
我在日志中看到的错误如下:
[INFO] java.lang.IllegalStateException: method_info is not set in the request
[INFO] at com.google.api.server.spi.auth.EspAuthenticator.authenticate(EspAuthenticator.java:67)
[INFO] at com.google.api.server.spi.request.Auth.authenticate(Auth.java:100)
[INFO] at com.google.api.server.spi.request.ServletRequestParamReader.getUser(ServletRequestParamReader.java:191)
[INFO] at com.google.api.server.spi.request.ServletRequestParamReader.deserializeParams(ServletRequestParamReader.java:136)
[INFO] at com.google.api.server.spi.request.RestServletRequestParamReader.read(RestServletRequestParamReader.java:123)
[INFO] at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:350)
[INFO] at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:114)
[INFO] at com.google.api.server.spi.handlers.EndpointsMethodHandler$RestHandler.handle(EndpointsMethodHandler.java:102)
[INFO] at com.google.api.server.spi.dispatcher.PathDispatcher.dispatch(PathDispatcher.java:49)
[INFO] at com.google.api.server.spi.EndpointsServlet.service(EndpointsServlet.java:71)
[INFO] at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
我已经尝试将完全相同的代码部署到 App Engine,并且效果很好。我试过调试 EspAuthenticator,它似乎期望 Servlet 过滤器在请求中注入一些属性。
我花了一些时间和一些调试才意识到应该注入 method_info 的过滤器没有被触发。
我可以通过修改 web.xml 中的映射来修复它,添加以下调度程序标签:
<filter-mapping>
<filter-name>endpoints-api-configuration</filter-name>
<servlet-name>EndpointsServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
我收到了同样的错误消息,最终追踪到在 URL 中使用尾随 /
发出请求,而我的 API 没有指定。尾部斜杠只会导致提供授权令牌的调用出错。
显然 ControlFilter
(因此 GoogleAppEngineControlFilter
)没有将其识别为有效端点,因此没有费心将 method_info
附加到请求中。但后来 EndpointsServlet
认为它 是 有效的,并试图在没有所有需要的信息的情况下进行身份验证!
修复很简单:删除我请求中 URL 的尾部斜线。然而,追查问题并非如此!我知道这不是你的问题,但也许这个答案会对其他人有所帮助。
生成并部署 OpenAPI 配置文件
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
$ mvn appengine:run
@Kevendra 的回答强调,如果 openapi.json
文件缺少对端点 API 方法的引用,则可能会导致此问题。 Firebase 可能会使用它来引用和发现 API 方法。
来自Google打开API概述:
Basic structure of an OpenAPI document:
An OpenAPI document describes the surface of your REST API, and defines information such as:
The name and description of the API. The individual endpoints (paths) in the API. How the callers are authenticated.
按照以下步骤重新生成和部署 openapi.json 文件:
生成:
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
mvn clean
- 运行 清理项目的 Maven 目标。package
- 编译打包endpoints-framework:openApiDocs
generate OpenAPI documents. This will generate theopenapi.json
file at the location:target/openapi-docs/openapi.json
- see generating and deploying an api configuration.-DskipTests
跳过 运行ning 任何测试,以避免任何测试失败 openapi.json 尚未生成
部署:
(作为预防措施,您可以先验证从以下命令返回的项目 ID,以确保服务不是在错误的项目中创建的 - gcloud config list project
)
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
从其生成的位置部署 openapi.json 文件(在上面的 'generate' 步骤中)。请参阅 Deploying the OpenAPI document
上的 Google 文档