Google consent screen not shown as expected

2019-01-28 21:18发布

问题:

I have registered a web application at cloud.google.com. "The OAuth 2.0 Client ID" looks like this:

I am using grails and the grails oauth plugin. In Config.groovy I added the follwoing snippet:

google {
    api = GoogleApi
    key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com'
    secret = 'yyyyyyyyyyyyyyyyyyyyyyyy'

    scope = 'https://www.googleapis.com/auth/userinfo.profile'

    callback = "http://localhost:8080/grailsOauthPluginDemo/oauth/google/callback"
    successUri = "http://localhost:8080/grailsOauthPluginDemo/oauthCallBack/google"
    failureUri = "http://localhost:8080/grailsOauthPluginDemo/oauthCallBack/failure"
}

and the following into index.gsp

<oauth:connect provider="google">Google</oauth:connect><br/>

I am logged in with my personal google account. I am using the https://github.com/manishkbharti/grailsOauthPluginDemo and when clicking the Google link I get to the consent page which looks like this:

I was expecting to get a page looking something like the following with my applications name. I know that I have to add a picture but the applications name should popup.

回答1:

I believe that the grailsOauthPluginDemo is using Google's OAuth1.0a API which currently uses different templates for the consent page.

Hope that helps!



回答2:

Thanks @svaret for trying the application.

I have updated the application, now it is using oauth2 for Google authentication.

Have a try.


Solution:-

Create a file in src/java, e.g., Google2Api.java and paste the following code(Ref# https://gist.github.com/yincrash/2465453)

package yourPackate;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.scribe.exceptions.OAuthException;
import org.scribe.extractors.AccessTokenExtractor;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthConstants;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuth20ServiceImpl;
import org.scribe.oauth.OAuthService;
import org.scribe.utils.OAuthEncoder;
import org.scribe.utils.Preconditions;

/**
 * Google OAuth2.0 
 * Released under the same license as scribe (MIT License)
 * @author yincrash
 * 
 */
public class Google2Api extends DefaultApi20 {

private static final String AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%s&redirect_uri=%s";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";

@Override
public String getAccessTokenEndpoint() {
    return "https://accounts.google.com/o/oauth2/token";
}

@Override
public AccessTokenExtractor getAccessTokenExtractor() {
    return new AccessTokenExtractor() {

        @Override
        public Token extract(String response) {
            Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string");

            Matcher matcher = Pattern.compile("\"access_token\" : \"([^&\"]+)\"").matcher(response);
            if (matcher.find())
            {
              String token = OAuthEncoder.decode(matcher.group(1));
              return new Token(token, "", response);
            } 
            else
            {
              throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
            }
        }
    };
}

@Override
public String getAuthorizationUrl(OAuthConfig config) {
    // Append scope if present
    if (config.hasScope()) {
        return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(),
                OAuthEncoder.encode(config.getCallback()),
                OAuthEncoder.encode(config.getScope()));
    } else {
        return String.format(AUTHORIZE_URL, config.getApiKey(),
                OAuthEncoder.encode(config.getCallback()));
    }
}

@Override
public Verb getAccessTokenVerb() {
    return Verb.POST;
}

@Override
public OAuthService createService(OAuthConfig config) {
    return new GoogleOAuth2Service(this, config);
}

private class GoogleOAuth2Service extends OAuth20ServiceImpl {

    private static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
    private static final String GRANT_TYPE = "grant_type";
    private DefaultApi20 api;
    private OAuthConfig config;

    public GoogleOAuth2Service(DefaultApi20 api, OAuthConfig config) {
        super(api, config);
        this.api = api;
        this.config = config;
    }

    @Override
    public Token getAccessToken(Token requestToken, Verifier verifier) {
        OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
        switch (api.getAccessTokenVerb()) {
        case POST:
            request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
            request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
            request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
            request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
            request.addBodyParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
            break;
        case GET:
        default:
            request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
            request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
            request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
            request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
            if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
        }
        Response response = request.send();
        return api.getAccessTokenExtractor().extract(response.getBody());
    }
}

}

and update google provider in Config.groovy

....
google {
    api = yourPackate.Google2Api
    ...
}
....

Note:- Package name must not be same as scribe api, i.e., org.scribe.builder.api. Make some thing different package name. I am using org.scribe.api.



回答3:

https://github.com/manishkbharti/grailsOauthPluginDemo already update the way to use Oauth2 for google. If you can't use Oauth2 from this Demo, you can look at grails plugin: Google for Spring Security OAuth plugin (https://github.com/donbeave/grails-spring-security-oauth-google). In their source code, they try to implement Oauth2 from DefaultApi20 class

I don't know why but I can only get the authorization code after the process, so I need to do an extra step to convert this code to an access token, here is the code in details:

def oauth2callback = { def code = params.code

    HttpTransport transport = new NetHttpTransport();
    JacksonFactory jsonFactory = new JacksonFactory();
    String CLIENT_ID = "....";
    String CLIENT_SECRET = "....";
    String REDIRECT_URI = ".....";

    GoogleTokenResponse response =
        new GoogleAuthorizationCodeTokenRequest(transport, jsonFactory, CLIENT_ID, CLIENT_SECRET, code, REDIRECT_URI).execute();

    GoogleCredential credential = new GoogleCredential.Builder().setClientSecrets(CLIENT_ID, CLIENT_SECRET)
            .setJsonFactory(jsonFactory).setTransport(transport).build()
            .setAccessToken(response.getAccessToken()).setRefreshToken(response.getRefreshToken());

    SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");
    service.setOAuth2Credentials(credential);
    // Define the URL to request.  This should never change.
    URL SPREADSHEET_FEED_URL = new URL(
            "https://spreadsheets.google.com/feeds/spreadsheets/private/full");

    // Make a request to the API and get all spreadsheets.
    SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
    List<SpreadsheetEntry> spreadsheets = feed.getEntries();

    spreadsheets.each {
        println it.getTitle().getPlainText()
    }
}