google - ¿Cómo obtener el token de acceso después de que el usuario haya iniciado sesión desde Gmail en Android?
obtener access token facebook (3)
Estoy siguiendo el inicio de sesión de Google para Android . Ahora puedo obtener el idToken pero mi servidor de servicios de fondo que he usado anteriormente está esperando el token de acceso, ya que estaba usando el inicio de sesión de Google+ anteriormente. Ahora no quiero alterar mi servidor. Pero aún así, ¿cómo puedo usar el inicio de sesión de Google y obtener el token de acceso en mi aplicación de Android para poder validar a mi usuario en mi servidor de servicios de fondo?
Estaba usando GooglePlay Service 7.5.0 anteriormente y ahora estoy usando GooglePlay Service más reciente 8.3.0.
BNK tiene la mancha en su mayor parte. La clase de actividad es la misma que la respuesta de BNK solo con la adición de la parte OkHttp una vez que obtiene GoogleSignInAccount
en el método onActivityResult()
.
Pero todavía estaba recibiendo errores con la parte de solicitud OkHttp. Finalmente, después de un poco de pruebas (y parte de la suerte) en Postman, descubrí que me faltaba el parámetro id_token. A la solicitud OkHttp le faltaba un parámetro, es decir, id_token. Use el token de ID que obtiene de GoogleSignInAccount algo como esto
GoogleSignInAccount acct = result.getSignInAccount();
String idTokenString = acct.getIdToken();
Ahora use este idTokenString junto con todos los parámetros en la parte de OkHttp de la respuesta de BNK de esta manera
...
RequestBody requestBody = new FormEncodingBuilder()
.add("grant_type", "authorization_code")
.add("client_id", "812741506391-h38jh0j4fv0ce1krdkiq0hfvt6n5amrf.apps.googleusercontent.com")
.add("client_secret", "{clientSecret}")
.add("redirect_uri","")
.add("code", "4/4-GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8")
.add("id_token", idTokenString) // Added this extra parameter here
.build();
...
La respuesta que se obtiene es la misma que la respuesta de BNK.
{
"access_token": "ya29.CjBgA_I58IabCJ...remainingAccessTokenHere",
"token_type": "Bearer",
"expires_in": 3577,
"id_token": "eyJhbGciOiJS...veryLongStringHere"
}
Ahora envíe este access_token a su servidor backend para autenticarse como solía hacer durante los tiempos de GoogleAuthUtil y PlusAPI.
Espero que esto ayude :) Gracias especiales a BNK!
En caso de que alguien más tenga problemas para realizar la solicitud final para obtener el token de acceso de google. A continuación se muestra un enfoque probado y de trabajo a partir del 11-01-2018. Utilizando retrofit2.
En primer lugar, aquí hay un enlace a google doc sobre el punto final de intercambio de tokens: https://developers.google.com/identity/protocols/OAuth2WebServer#exchange-authorization-code
public interface GoogleService {
@POST("token")
@FormUrlEncoded
@Headers("Content-Type:application/x-www-form-urlencoded")
Call<GoogleAuthData> getToken(
@Field("grant_type") String grantType,
@Field("client_id") String clientId,
@Field("client_secret") String clientSecret,
@Field("redirect_uri") String redirectUri,
@Field("code") String code);
}
Entonces llámalo así:
Call<GoogleAuthData> call = RetroClient.getGoogleService().getToken(
"authorization_code", context.getString(R.string.server_client_id),
context.getString(R.string.server_client_secret), "", authCode);
Para sus requerimientos, puede utilizar el siguiente código:
En primer lugar, asegúrese de tener un ID de cliente de Web OAuth 2.0 válido:
<!-- Server Client ID. This should be a valid Web OAuth 2.0 Client ID obtained
from https://console.developers.google.com/ -->
<string name="server_client_id">...e4p8.apps.googleusercontent.com</string>
Luego dentro de la clase de actividad:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
// For sample only: make sure there is a valid server client ID.
validateServerClientID();
// [START configure_signin]
// Configure sign-in to request offline access to the user''s ID, basic
// profile, and Google Drive. The first time you request a code you will
// be able to exchange it for an access token and refresh token, which
// you should store. In subsequent calls, the code will only result in
// an access token. By asking for profile access (through
// DEFAULT_SIGN_IN) you will also get an ID Token as a result of the
// code exchange.
String serverClientId = getString(R.string.server_client_id);
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
.requestServerAuthCode(serverClientId)
.requestEmail()
.build();
// [END configure_signin]
// Build GoogleAPIClient with the Google Sign-In API and the above options.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
private void getAuthCode() {
// Start the retrieval process for a server auth code. If requested, ask for a refresh
// token. Otherwise, only get an access token if a refresh token has been previously
// retrieved. Getting a new access token for an existing grant does not require
// user consent.
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_GET_AUTH_CODE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_GET_AUTH_CODE) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
Log.d(TAG, "onActivityResult:GET_AUTH_CODE:success:" + result.getStatus().isSuccess());
if (result.isSuccess()) {
// [START get_auth_code]
GoogleSignInAccount acct = result.getSignInAccount();
String authCode = acct.getServerAuthCode();
// Show signed-in UI.
mAuthCodeTextView.setText(getString(R.string.auth_code_fmt, authCode));
updateUI(true);
// TODO(user): send code to server and exchange for access/refresh/ID tokens.
// [END get_auth_code]
} else {
// Show signed-out UI.
updateUI(false);
}
}
}
Puede ver el código completo en el siguiente ServerAuthCodeActivity.java
El resultado, si usa esa muestra, se parece a la siguiente captura de pantalla:
Luego, puede seguir los pasos mencionados en la documentación de Google a continuación (del paso # 3. Envíe el código de autenticación al backend de su aplicación utilizando HTTPS POST ):
Inicio de sesión de Google para Android: habilitación del acceso del lado del servidor
ACTUALIZACIÓN: a partir de los comentarios, si desea obtener el token de acceso directamente desde la aplicación cliente de Android, use el siguiente código de muestra (reemplazado con su ID de cliente, cliente_secret y el código de autenticación)
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormEncodingBuilder()
.add("grant_type", "authorization_code")
.add("client_id", "812741506391-h38jh0j4fv0ce1krdkiq0hfvt6n5amrf.apps.googleusercontent.com")
.add("client_secret", "{clientSecret}")
.add("redirect_uri","")
.add("code", "4/4-GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8")
.build();
final Request request = new Request.Builder()
.url("https://www.googleapis.com/oauth2/v4/token")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(final Request request, final IOException e) {
Log.e(LOG_TAG, e.toString());
}
@Override
public void onResponse(Response response) throws IOException {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
final String message = jsonObject.toString(5);
Log.i(LOG_TAG, message);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Utilice la compile ''com.squareup.okhttp:okhttp:2.6.0''
(la compile ''com.squareup.okhttp:okhttp:2.6.0''
3-RC1 tendrá diferentes clases)
Con una respuesta exitosa, tendrá la siguiente información en logcat:
I/onResponse: {
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "1//xz1eb0XU3....nxoALEVQ",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjQxMWY1Ym......yWVsUA",
"access_token": "ya29.bQKKYah-........_tkt980_qAGIo9yeWEG4"
}