问题
So I am running the sample code provided by 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;
}
}
I am getting a Firebase token from my Android client and try to send it to the backend by:
curl -H "Authorization: Bearer FIREBASE_JWT_TOKEN" \
-X GET \
http://localhost:8080/_ah/api/echo/v1/firebase_user
The error I see in the logs is the following:
[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)
I have tried deploying the exact same code to App Engine and it works perfectly. I have tried debugging EspAuthenticator and it seems that it is expecting the Servlet filters to inject some attributes in the request.
回答1:
It took me a while and a bit of debugging to realize that the filter that is supposed to inject method_info was not being fired.
I could fix it by modifying the mapping in web.xml adding the following dispatcher tags:
<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>
回答2:
generat and deploy the OpenAPI configuration file
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
$ mvn appengine:run
回答3:
I got the same error message, and eventually tracked it down to making a request with a trailing /
in the URL where my API did not specify one. The trailing slash only causes an error for calls that provide an authorization token.
Apparently ControlFilter
(and therefore also GoogleAppEngineControlFilter
) did not recognize it as a valid endpoint and therefore did not bother attaching method_info
to the request. But then EndpointsServlet
thought it was valid and tried to authenticate without all the needed info!
The fix was easy: remove the trailing slash from the URL in my request. Tracking down the problem, however, was not! I see this was not your problem, but maybe this answer will help someone else.
回答4:
@Kevendra's answer highlights that this issue can be caused if an openapi.json
file is missing a reference to the endpoint API method. Firebase may be using this to reference and discover the API method.
From the Google OpenAPI Overview:
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.
Follow these steps to regenerate and deploy the openapi.json file:
generate:
$ mvn clean package endpoints-framework:openApiDocs -DskipTests
mvn clean
- run a Maven goal to clean your project.package
- compile and package it- 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
skips running any tests, to avoid any test failure due to the openapi.json not yet being generated
deploy:
(As a precaution you can first validate the project ID returned from the following command to make sure that the service isn't created in the wrong project - gcloud config list project
)
$ gcloud endpoints services deploy target/openapi-docs/openapi.json
Deploys the openapi.json file from its generated location (in the 'generate' step above). See the Google docs on Deploying the OpenAPI document
来源:https://stackoverflow.com/questions/42749021/google-cloud-endpoints-firebase-auth-method-info-is-not-set