Use this file to discover all available pages before exploring further.
Ce document fait partie du scénario d’architecture Mobile + API et explique comment mettre en œuvre l’application mobile avec Android. Veuillez vous référer au scénario pour obtenir des informations sur la solution mise en œuvre.
La LoginActivity traite l’autorisation de l’utilisateur et correspond à l’écran initial que les utilisateurs voient. Nous allons créer une méthode login() pour initialiser un WebAuthProvider et lancer l’authentification. Assurez-vous de fournir le bon schéma, la bonne et la bonne permission au WebAuthProvider. Pour cette mise en œuvre, nous utiliserons :
permission : create:timesheets read:timesheets openid profile email offline_access. Ces permissions nous permettront d’envoyer POST et GET à l’API Node.JS, ainsi que de récupérer le profil utilisateur et un jeton d’actualisation.
Nous utiliserons le CredentialsManager de la bibliothèque Auth0.Android et SharedPreferences pour stocker les identifiants reçus après la connexion.Nous pouvons créer le CredentialsManager avant d’initialiser le WebAuthProvider dans la méthode login(). La transmission d’un AuthenticationAPIClient au CredentialsManager lui permet d’actualiser les jetons d’accès s’ils ont expiré.
private void login() { Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain)); auth0.setOIDCConformant(true); AuthenticationAPIClient authAPIClient = new AuthenticationAPIClient(auth0); SharedPreferencesStorage sharedPrefStorage = new SharedPreferencesStorage(this); final CredentialsManager credentialsManager = new CredentialsManager(authAPIClient, sharedPrefStorage); WebAuthProvider.init(auth0) // ... }
Mettez maintenant à jour la méthode login() pour que les identifiants soient stockés via le CredentialsManager après une authentification réussie.
// ...@Overridepublic void onSuccess(@NonNull final Credentials credentials) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show(); } }); credentialsManager.saveCredentials(credentials); startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));// ...}
Pour gérer le stockage des informations relatives au profil de l’utilisateur, nous allons créer une classe de gestionnaire, UserProfileManager. Le UserProfileManager utilisera SharedPreferences pour stocker les données.
package com.auth0.samples.utils;import android.content.Context;import android.content.SharedPreferences;import com.auth0.android.result.UserProfile;import com.auth0.samples.models.User;public class UserProfileManager { private static final String PREFERENCES_NAME = "auth0_user_profile"; private static final String EMAIL = "email"; private static final String NAME = "name"; private static final String PICTURE_URL = "picture_url"; public static void saveUserInfo(Context context, User userInfo) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, userInfo.getEmail()) .putString(NAME, userInfo.getName()) .putString(PICTURE_URL, userInfo.getPictureURL()) .apply(); } public static User getUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); return new User( sp.getString(EMAIL, null), sp.getString(NAME, null), sp.getString(PICTURE_URL, null) ); } public static void deleteUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, null) .putString(NAME, null) .putString(PICTURE_URL, null) .apply(); }}
Mettez ensuite à jour la méthode login() dans LoginActivity pour récupérer le jeton d’ID et obtenir le profil de utilisateur à partir du jeton avec la bibliothèque JWTDecode.Android. Stockez ensuite le profil utilisateur avec UserProfileManager.
// ...@Overridepublic void onSuccess(@NonNull final Credentials credentials) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show(); } }); credentialsManager.saveCredentials(credentials); JWT jwt = new JWT(credentials.getIdToken()); User user = new User( jwt.getClaim("email").asString(), jwt.getClaim("name").asString(), jwt.getClaim("picture").asString() ); UserProfileManager.saveUserInfo(LoginActivity.this, user); startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));}// ...
4. Afficher les éléments de l’interface utilisateur de manière conditionnelle en fonction de la permission
Pour déterminer si un utilisateur a les autorisations requises pour effectuer certaines actions, nous pouvons examiner la permission scope qui a été accordée à l’utilisateur au cours du processus d’authentification. La permission scope contiendra une chaîne avec toutes les permissions accordées à un utilisateur, de sorte que pour déterminer si une permission particulière a été accordée, il suffit de regarder si la chaîne des permissions contient la sous-chaîne de cette permission particulière.
Tout d’abord, nous pouvons mettre à jour la classe User pour stocker les permissions accordées, puis fournir une méthode d’aide, hasScope(), qui peut être utilisée pour déterminer si les permissions accordées contiennent une permission donnée.
public class User { private String email; private String name; private String pictureURL; private String grantedScope; public User(String email, String name, String pictureURL, String grantedScope) { this.email = email; this.name = name; this.pictureURL = pictureURL; this.grantedScope = grantedScope; } public String getEmail() { return email; } public String getGrantedScope() { return grantedScope; } public String getName() { return name; } public String getPictureURL() { return pictureURL; } public Boolean hasScope(String scope) { return grantedScope.contains(scope); }}
N’oubliez pas non plus de mettre à jour le UserProfileManager afin de stocker le champ supplémentaire :
public class UserProfileManager { private static final String PREFERENCES_NAME = "auth0_user_profile"; private static final String EMAIL = "email"; private static final String NAME = "name"; private static final String PICTURE_URL = "picture_url"; private static final String SCOPE = "scope"; public static void saveUserInfo(Context context, User userInfo) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, userInfo.getEmail()) .putString(NAME, userInfo.getName()) .putString(PICTURE_URL, userInfo.getPictureURL()) .putString(SCOPE, userInfo.getGrantedScope()) .apply(); } public static User getUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); return new User( sp.getString(EMAIL, null), sp.getString(NAME, null), sp.getString(PICTURE_URL, null), sp.getString(SCOPE, null) ); } public static void deleteUserInfo(Context context) { SharedPreferences sp = context.getSharedPreferences( PREFERENCES_NAME, Context.MODE_PRIVATE); sp.edit() .putString(EMAIL, null) .putString(NAME, null) .putString(PICTURE_URL, null) .putString(SCOPE, null) .apply(); }}
Mettez ensuite à jour la LoginActivity pour transmettre la permission scope afin qu’elle puisse être stockée dans l’objet User :
// ...@Overridepublic void onSuccess(@NonNull final Credentials credentials) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show(); } }); credentialsManager.saveCredentials(credentials); JWT jwt = new JWT(credentials.getIdToken()); String scopes = credentials.getScope(); User user = new User( jwt.getClaim("email").asString(), jwt.getClaim("name").asString(), jwt.getClaim("picture").asString(), credentials.getScope() ); UserProfileManager.saveUserInfo(LoginActivity.this, user); startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));}// ...
Affichage du menu d’approbation basé sur la permission
Nous pouvons désormais afficher certains éléments de l’interface utilisateur en fonction de la permission accordée à l’utilisateur. Par exemple, nous avons un élément du menu d’approbation qui ne doit être visible que par les utilisateurs qui ont reçu la permission approve:timesheets.Vous pouvez voir ci-dessous le code de la classe BaseActivity qui vérifie si un utilisateur dispose de la permission approve:timesheets et qui, en fonction de cela, définit la visibilité de l’élément de menu qui affiche l’activité d’approbation.
La TimeSheetActivity affiche les entrées de la feuille de temps de l’utilisateur connecté qui sont stockées sur le serveur.
@string/api_url est définie sur http://10.0.2.2:8080/timesheets de manière à ce que l’émulateur Android puisse se connecter à l’API Node.JS s’exécutant sur http://localhost:8080.
La méthode callAPI() récupère les feuilles de temps à partir de l’API Node.JS.
La méthode processResults() prend la réponse JSON de callAPI() et la convertit en objets TimeSheet.
Les méthodes onCreateOptionsMenu() et onOptionsItemSelected() gèrent la fonctionnalité de navigation du gadget logiciel de la barre d’outils.
Pour afficher le profil de l’utilisateur connecté, nous allons créer UserActivity, un modèle user_activity.xml correspondant et le fichier user_action_menu.xml pour la navigation dans la barre d’outils. L’écran affiche le nom de l’utilisateur, son courriel et sa photo de profil.
Dans la méthode onCreate() nous allons récupérer les informations de l’utilisateur dans le UserProfileManager et définir les valeurs affichées. Comme précédemment, les méthodes onCreateOptionsMenu() et onOptionsItemSelected() gèrent la fonctionnalité de navigation du gadget logiciel de la barre d’outils.
package com.auth0.samples.activities;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.widget.ImageView;import android.widget.TextView;import com.auth0.samples.R;import com.auth0.samples.utils.ImageTask;import com.auth0.samples.utils.UserProfileManager;public class UserActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.user_activity); Toolbar navToolbar = (Toolbar) findViewById(R.id.navToolbar); setSupportActionBar(navToolbar); TextView tvName = (TextView) findViewById(R.id.tvName); TextView tvEmail = (TextView) findViewById(R.id.tvEmail); tvName.setText(UserProfileManager.getUserInfo(this).getName()); tvEmail.setText(UserProfileManager.getUserInfo(this).getEmail()); new ImageTask((ImageView) findViewById(R.id.ivPicture)) .execute(UserProfileManager.getUserInfo(this).getPictureURL()); UserProfileManager.getUserInfo(this).getName(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu items for use in the action bar MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.user_action_menu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_new: startActivity(new Intent(UserActivity.this, FormActivity.class)); break; case R.id.action_view: startActivity(new Intent(UserActivity.this, TimeSheetActivity.class)); break; default: // If we got here, the user's action was not recognized. // Invoke the superclass to handle it. return super.onOptionsItemSelected(item); } return true; }}
@string/api_url est définie sur http://10.0.2.2:8080/timesheets de manière à ce que l’émulateur Android puisse se connecter à l’API Node.JS s’exécutant sur http://localhost:8080.
La méthode onCreate() initialise le formulaire et collecte les données pour la méthode postAPI() lorsque l’on appuie sur le bouton de soumission.
La méthode postAPI() enverra les données de l’utilisateur extraites du formulaire à l’API Node.JS au format JSON.
La méthode clearForm() vide les formulaires de saisie.
Les méthodes onCreateOptionsMenu() et onOptionsItemSelected() gèrent la fonctionnalité de navigation du gadget logiciel de la barre d’outils.
Start the API by navigating to the API’s directory in your terminal and entering the node server command.
Ouvrez l’application mobile dans Android Studio et appuyez sur le bouton Exécuter.
Sélectionnez l’appareil virtuel Nexus 5X API 23.
Une fois que l’émulateur a chargé l’application mobile, vous pouvez vous connecter en tant qu’utilisateur, puis créer et afficher des entrées de feuilles de temps à partir de l’API Node.JS en cours d’exécution.