Java based Google App Engine, Android and authenti

2019-04-02 08:56发布

Authentication and app engine, there is a lot to be read about it, but a lot seems to be outdated!

Even the google pages https://developers.google.com/appengine/docs/java/endpoints/consume_android#making-authenticated-calls

Here, they talk about 'GoogleAccountCredential.usingAudience', but nowadays, you should use GoogleAuthUtil (as far as I know, please correct me if I'm wrong).

I am trying to set up an app engine as a backend to my Android app (and in future, my iOS app).

I am using Android Studio, used the 'new module' and chose app engine with cloud messaging there.

I created a simple endpoint, and have a function there, here is some code:

public class ReviewEndpoint {

// Make sure to add this endpoint to your web.xml file if this is a web application.

private static final Logger LOG = Logger.getLogger(ReviewEndpoint.class.getName());

/**
 * This method gets the <code>Review</code> object associated with the specified         <code>id</code>.
 * @param id The id of the object to be returned.
 * @return The <code>Review</code> associated with <code>id</code>.
 */
@ApiMethod(name = "getReview")
public Review getReview(@Named("id") Long id) {
    // Implement this function
    Review r = new Review();
    r.setData("test!");

As you can see, this is nicely generated by Android Studio. I implemented some stuf like creating the 'review' object and return it at the end.

On the Android side, I can do this:

ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null);
ReviewEndpoint ep = b.build();
Review review = ep.getReview(1L).execute();
data = review.getData();

and yes, I get 'test!' :)

Now, I want to have this authenticated. I want to know which user wrote what, so I thought I am going to use GMail account and Facebook later.

Here I'm stuck. I am able to get a token from the user on Android:

token = GoogleAuthUtil.getToken(MainScreenActivity.this, mAccount.name, "oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.profile");

then you are able to add this token as credential to the request:

Credential cr = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(token);
ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), cr);

Then in the app engine I tried to get the user info, but how? Will it be supplied as 'bearer'? How do I get this bearer token? Should I then do API request to get the data on the server?

this does not work:

OAuthService service = OAuthServiceFactory.getOAuthService();
try {
    User user = service.getCurrentUser();

can anyone give me a heads up?

1条回答
一纸荒年 Trace。
2楼-- · 2019-04-02 09:31

So finally, today, I found out how to do it! I had questions on Stackoverflow on this before and never had an answer, but these to sites gave me the answer:

https://developers.google.com/appengine/docs/java/endpoints/auth

https://developers.google.com/appengine/docs/java/endpoints/consume_android

The first shows what needs to be done on the app engine side. The second page will tell you how to get the credentials. I was quite close. I am not sure if the adjusting of the build.gradle file mentioned in the second link is necessary. What I added to the App Engine:

@Api(name = "reviewEndpoint", version = "v1", ...<<some more stuff here >>
    scopes = {Constants.EMAIL_SCOPE},
    clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID},
    audiences = {Constants.ANDROID_AUDIENCE})

and then get the credentials:

// Initialize the scope using the client ID you got from the Console.
final String scope = "server:client_id:" + Constants.WEB_CLIENT_ID;

credential = GoogleAccountCredential.usingAudience(activity,scope);

You have to add the e-mail address of the user:

credential.setSelectedAccountName("some-mail-address@gmail.com");

you can get the e-mail address using the account picker (also example shown when you follow the link)

and next. you do a call to the endpoint, using the credential, I think Play Services will validate the user, because if I use an e-mail that is not logged in on the device, it will not work. The following code will throw an GoogleAuthIOException :

ReviewEndpoint.Builder b = new ReviewEndpoint.Builder(
    AndroidHttp.newCompatibleTransport(), 
    new AndroidJsonFactory(), id_token);
ReviewEndpoint ep = b.build();
Review review;
review = ep.getReview(1L).execute();

for testing, I've put the e-mail address I get at the server side as a string in the review object, and there it gave me the e-mail address instead of the user object being null. Ow! I forgot to tell you, you need a user argument on the app engine side. Even though you do not see the 'user' argument in the 'getReview' call above, it will be added by App Engine.

So this is how my getReview looks now:

@ApiMethod(name = "getReview")
public Review getReview(@Named("id") Long id, User user) {
    // Implement this function
    Review r = new Review();

    r.setData("user == " + (user == null ? "NULL " : user.toString()));

Hope this will help someone

查看更多
登录 后发表回答