- Azure
- Xamarin
- Xamarin.Forms
- Xamarin.iOS
- Xamarin.Android
Lors du développement d’une application mobile, vous avez souvent besoin d’un système d’authentification pour vos utilisateurs. Créer un nouveau compte pour un usage spécifique, cela peut constituer un frein pour certains utilisateurs. Vos utilisateurs auront probablement déjà un compte Google, Facebook, Github ou Microsoft. Alors pourquoi ne pas utiliser l’un d’eux au lieu de multiplier le nombre de comptes ?
Dans ce tutoriel, je vais vous montrer comment authentifier vos applications Xamarin à l’aide du système d’authentification Microsoft.
Voici quelques avantages de l’utilisation de cette technique :
IdToken
à partir de la connexion associée et l’utiliser avec Open Id Connect pour autoriser l’accès à une API Web.Avant de pouvoir connecter vos utilisateurs à leur compte Microsoft, nous devons enregistrer une application sur le Portail Azure
. Cette application est utilisée pour déclarer le type de compte d’utilisateur autorisé à se connecter avec son compte Microsoft dans votre application.
Commençons donc par vous rendre sur le site Web Azure Portal. Dans le menu de gauche, sélectionnez Azure Active Directory, puis App registratons, puis cliquez sur New registration en haut de l’écran.
Ensuite :
Maintenant, si vous ouvrez votre application, dans l’onglet Overview, vous trouverez votre Application (client) ID. Cet identifiant d’application sera utilisé pour identifier et autoriser votre application Xamarin, qui est obligatoire pour authentifier les utilisateurs à l’aide de leur compte Microsoft.
Nous avons maintenant la configuration de notre application Azure, passons à l’étape suivante: intégrer l’authentification Microsoft dans notre application Xamarin. Tout d’abord, installons le package Nuget Microsoft.Identity.Client
à votre code partagé et vos projets de chaque plateformes.
Créons une nouvelle classe appelée MicrosoftAuthService
où nous allons implémenter 4 méthodes :
public class MicrosoftAuthService : IMicrosoftAuthService
{
private readonly string ClientID = "REPLACE_WITH_YOUR_APP_ID";
private readonly string[] Scopes = { "User.Read" };
private readonly string GraphUrl = "https://graph.microsoft.com/v1.0/me";
private IPublicClientApplication publicClientApplication;
public void Initialize()
{
this.publicClientApplication = PublicClientApplicationBuilder.Create(ClientID)
.WithIosKeychainSecurityGroup("com.microsoft.adalcache")
.WithRedirectUri($"msal{ClientID}://auth")
.Build();
}
/// <summary>
/// This object is used to know where to display the authentication activity (for Android) or page.
/// </summary>
public static object ParentWindow { get; set; }
/// <summary>
/// Signin with your Microsoft account.
/// </summary>
public async Task<User> OnSignInAsync()
{
User currentUser = null;
var accounts = await this.publicClientApplication.GetAccountsAsync();
try
{
try
{
var firstAccount = accounts.FirstOrDefault();
var authResult = await this.publicClientApplication.AcquireTokenSilent(Scopes, firstAccount).ExecuteAsync();
currentUser = await this.RefreshUserDataAsync(authResult?.AccessToken).ConfigureAwait(false);
}
catch (MsalUiRequiredException ex)
{
// the user was not already connected.
try
{
var authResult = await this.publicClientApplication.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow(ParentWindow)
.ExecuteAsync();
currentUser = await this.RefreshUserDataAsync(authResult?.AccessToken).ConfigureAwait(false);
}
catch (Exception ex2)
{
// Manage the exception with a logger as you need
System.Diagnostics.Debug.WriteLine(ex2.ToString());
}
}
}
catch (Exception ex)
{
// Manage the exception with a logger as you need
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
return currentUser;
}
/// <summary>
/// Sign out with your Microsoft account.
/// </summary>
public async Task OnSignOutAsync()
{
var accounts = await this.publicClientApplication.GetAccountsAsync();
try
{
while (accounts.Any())
{
await this.publicClientApplication.RemoveAsync(accounts.FirstOrDefault());
accounts = await this.publicClientApplication.GetAccountsAsync();
}
}
catch (Exception ex)
{
// Manage the exception with a logger as you need
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
/// <summary>
/// Refresh user date from the Graph api.
/// </summary>
/// <param name="token">The user access token.</param>
/// <returns>The current user with his associated informations.</returns>
private async Task<User> RefreshUserDataAsync(string token)
{
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, this.GraphUrl);
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
User currentUser = null;
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
currentUser = JsonConvert.DeserializeObject<User>(json);
}
return currentUser;
}
}
Expliquons cette classe :
Nous devons d’abord déclarer le ClientID
que nous avons récupéré du portail Azure. Ensuite, la méthode Initialize
initialisera le PublicClientApplication
avec notre Application (client) ID. Pour iOS, nous devons appeler la méthode WithIosKeychainSecurityGroup
pour permettre à l’application d’accéder au trousseau (Keychain) de l’appareil.
La méthode OnSignInAsync
affichera automatiquement la Webview d’authentification Microsoft. Nous vérifions d’abord si un compte est déjà présent sur l’appareil, si c’est le cas, le compte sera automatiquement proposé à l’utilisateur. Nous passons un Scope qui représente la liste des éléments auxquels nous souhaitons avoir accès. Ici, nous voulons seulement lire les informations de l’utilisateur donc nous utilisions: User.Read
La méthode OnSignOutAsync
supprime tous les comptes connectés sur l’appareil.
Enfin, RefreshUserDataAsync
appellera la Graph Api de Microsoft pour obtenir des détails sur le compte d’utilisateur.
Je vous recommanderai de créer l’interface associée à ce service pour pouvoir utiliser l’injection de dépendance dans un projet réel.
Pour Android, vous devez suivre les 3 étapes suivantes :
Tout d’abord, allez dans votre MainActivity.cs
et overridez la méthode OnActivityResult
et ajoutez-y cette ligne :
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
Cela garantira que le contrôle reviendra à MSAL (Microsoft Authentication Library) lorsque la partie interactive du flux d’authentification sera terminée.
Seconde étape, ajoutez cette ligne à la fin de votre méthode OnCreate
, cela garantira que les flux d’authentification se produisent dans le contexte de l’activité en cours.
MicrosoftAuthService.ParentWindow = this;
Dernière étape pour Android, allez dans le fichier AndroidManifest.xml
et déclarez une nouvelle activité comme ceci:
<application android:label="MicrosoftDemoProject.Android">
<activity android:name="microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="msalREPLACE_WITH_YOUR_APP_ID" android:host="auth" />
</intent-filter>
</activity>
</application>
Cette activité est utilisée pour afficher la page d’authentification Microsoft dans une activité spécifique. Assurez-vous de configurer correctement l’Application (client) ID.
Pour le projet iOS, vous devez suivre ces 3 étapes :
Tout d’abord, allez dans la classe AppDelegate.cs
et overridez la méthode suivante :
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return true;
}
Comme nous l’avons fait dans le projet Android, cette ligne assurera le bon fonctionnement de MSAL.
La prochaine étape consiste à activer les Keychain Groups dans le fichier Entitlements.plist
et à spécifier un KeyChain Group avec com.microsoft.adalcache afin de permettre à l’application d’accéder au trousseau de l’appareil.
Ouvrez ensuite les paramètres du projet et dans iOS Bundle Signing, sélectionnez Entitlements.plist dans la propriété Custom Entitlements.
Si vous ne le faites pas correctement, vous obtiendrez ce genre d’erreur:
Microsoft.Identity.Client.MsalClientException: The application cannot access the iOS keychain for the application publisher (the TeamId is null). This is needed to enable Single Sign On between applications of the same publisher. This is an iOS configuration issue. See https://aka.ms/msal-net-enable-keychain-access for more details on enabling keychain access.
Dernière étape, allez dans le fichier Info.plist
et ajoutez ces lignes :
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.companyname.MicrosoftDemoProject</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msalREPLACE_WITH_YOUR_APP_ID</string>
</array>
</dict>
</array>
Ceci sera utilisé lorsque l’application ouvrira l’URL d’authentification MSAL. N’oubliez pas de configurer correctement l’Application (client) ID et de changer le CFBundleURLName
avec le Bundle identifier de votre projet.
J’ai créé un exemple simple et complet de ce code en utilisant l’injection de dépendance avec MvvmLightLibs
pour vous montrer un exemple complet avec une architecture simple.
Vous trouverez un exemple de code sur ce répertoire Github.
Happy codding !
Vous avez aimé ce tutoriel ? Laissez une étoile sur le répertoire Github associé !