Je découvre, un peu tard, comment on peut récupérer et utiliser un token d’authentification sur Android. Le but de cet article est de se connecter à un Google Site (sites.google.com) ou n’importe quel autre service Google depuis un device Android, en utilisant le comptes installé sur notre device.
On récupère son AccountManager, qui va nous servir d’une part à lister les comptes disponibles sur votre device, d’autre part à récupérer le token d’authentification.
AccountManager accountManager = AccountManager.get(mContext);
//avec mContext votre activité, contexte...
Si on veut, on peut filtrer nous-mêmes sur les comptes d’utilisateur comme ça:
for (Account a : accountManager.getAccounts())
{
if(a.name.contains("@www.oxiane.com")){
Log.d("toto", "trouvé un compte oxiane! "+a.name+ " "+a.type);
}
}
Sinon, en spécifiant le type de compte, Android nous affiche une popup pour sélectionner un compte. Par exemple, pour un compte Google, on met
« com.google » dans le type de compte.
accountManager.getAuthTokenByFeatures("com.google", SCOPES, null, mContext, null, null, new MyAccManagerCallBack(), null);
//Si on a déjà fait le tri sur les comptes, pas besoin de lister tous les comptes Google.
//ici on fait l'appel pour obtenir un token d'authent avec un Account a
accountManager.getAuthToken(a, SCOPES, null, true, new MyAccManagerCallBack(), null);
La constante SCOPES utilisée plus haut permet de spécifier quels services notre token pourra utiliser.
Par exemple, si on veut avoir accès aux infos de l’utilisateur, il faut écrire dans notre scope « oauth2:https://www.googleapis.com/auth/userinfo.email ». Si on veut accéder à d’autres services, on peut simplement rajouter des urls après cette valeur, avec un espace. Pour connaître la liste des services Google disponibles avec un token d’authentification, le plus simple est d’aller faire un tour sur le site de playground oauth/.
Puis, lorsqu’on exécute notre requête sur le playground oauth, bien regarder les headers utilisés:
Dans cet exemple, comme le but est de se connecter à sites.google.com et d’obtenir les informations de l’utilisateur en JSON, voici la constante SCOPES utilisée:
private final String SCOPES = "oauth2:https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://sites.google.com/feeds/";
Lorsque la requête d’authentification est effectuée, un AccountManagerCallBack est appelé, celui que nous avons spécifié plus haut:
private final class OxAccManagerCallBack implements AccountManagerCallback<Bundle> {
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
//On peut récupérer, si besoin, l'account name et type
//bundle.getString(AccountManager.KEY_ACCOUNT_NAME);
//bundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
//bim on a récupéré notre token!
} catch (Exception e) {
System.out.println("getAuthTokenByFeatures() cancelled or failed:");
e.printStackTrace();
authToken = "failure";
}
if(!authToken.equals("failure")) {
new GetWikiFeedTask().execute(new Void[]{});
}
}
}
Dans mon exemple, je vais utiliser le token pour aller chercher le contenu du feed du Wiki d’Oxiane, qui se trouve sur un site Google. La clé ici, c’est d’utiliser un Header Http « Authorization: Bearer » et votre token. Il faut aussi rajouter le header « Gdata-version: 1.4 ». Attention, il vaut mieux faire le test sur le playground oauth pour être sûr de la syntaxe et des headers http à fournir.
Concrètement, ce qui est fait ici, c’est l’initialisation de la requête http avec HttpClient avec les headers qui vont bien, l’exécution de la requête et la copie du flux vers un fichier « toto.html » sur la SDcard.
private class GetWikiFeedTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
HttpClient c = new DefaultHttpClient();
HttpGet get = new HttpGet("https://sites.google.com/feeds/content/www.oxiane.com/wiki");
get.setHeader("Gdata-version", "1.4");
get.setHeader("Authorization", "Bearer "+authToken);
try {
HttpResponse r = c.execute(get);
copyStream(r.getEntity().getContent(), new File(Environment.getExternalStorageDirectory(), "toto.html"));
} catch (IOException e) {
Log.d("toto", "erreur");
e.printStackTrace();
}
return null;
}
}
Ne pas oublier les permissions!
<uses-permission android:name="android.permission.INTERNET" />
<!-- USE_CREDENTIALS is necessary for Google+ login -->
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<!-- GET_ACCOUNTS is necessary to display email address of logged in user. This permission is optional -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
On peut, si on veut, sauvegarder le token dans les préférences de l’application (encrypté, c’est mieux). Il faudra dans ce cas gérer les codes retour de nos requêtes (401 forbidden, notamment) et rappeler getAuthToken() pour récupérer un nouveau token.