Récupérer les informations utilisateurs suite à une connexion via un provider externe avec ASP.NET Core RC1

Gérer l’authentification des utilisateurs, via des providers externes (LinkedIn, Facebook, Microsoft, etc.) depuis une application ASP .NET est très simple avec ASP .NET Identity qui, grâce à des packages Nuget (Microsoft.Owin.Security.*), permet de proposer des méthodes d’extension telles que UseMicrosoftAccountAuthentication, UseFacebookAuthentication, UseLinkedInAuthentication, etc.:

app.UseFacebookAuthentication(
   appId: "Your App ID",
   appSecret: "Your App Secret");

Pour récupérer de plus amples informations sur l’utilisateur qui se connecte, il est nécessaire de faire plusieurs choses:

  • Rajouter, dans les scopes, les permissions demandées (à savoir le niveau d’information que l’on souhaite sur l’utilisateur)
  • Une fois la connexion effectuée, injecter, dans les Claims, les données de l’utilisateur

 

Si le premier point est trivial:

options.Scope.Add("user_friends");

Le deuxième peut s’avérer plus complexe, notamment depuis la RC1 d’ASP .NET Core. En effet, jusqu’à présent, il était possible d’utiliser ce type de code:

var options = new FacebookAuthenticationOptions
{
    AppId = "Your App ID",
    AppSecret = "Your App Secret",
    Provider = new FacebookAuthenticationProvider
    {
        OnAuthenticated = async context =>
        {
            // Retrieve the OAuth access token to store for subsequent API calls
            string accessToken = context.AccessToken;

            // Retrieve the username
            string facebookUserName = context.UserName;

            // You can even retrieve the full JSON-serialized user
            var serializedUser = context.User;
        }
    }
};
app.UseFacebookAuthentication(options);

Cependant, depuis la RC1, ce code n’est plus utilisable car la propriété Provider n’existe plus. Après de plus amples recherches en vain (la documentation sur ASP .NET Core a sérieusement besoin d’être mise à jour entre les différentes versions), la réponse m’a été fournie, suite à une question sur StackOverflow, par Pinpoint:

In ASP.NET Core, all the OAuth2 social providers (even the ones developed by the community) have been updated to use the new OAuth2 generic middleware.

As part of this change, we've removed the provider-specific classes to use a single events hook named OAuthEvents, which replaces Katana's FacebookAuthenticationProvider and co.

Autrement dit, voici la version à jour du code:

app.UseFacebookAuthentication((options) => 
{
    options.AppId = Configuration["Identity:FacebookAppId"];
    options.AppSecret = Configuration["Identity:FacebookAppSecret"];

    options.Scope.Add("email");
    options.Scope.Add("public_profile");
    options.SaveTokensAsClaims = true;
    options.BackchannelHttpHandler = new FacebookBackChannelHandler();
    options.UserInformationEndpoint = "https://graph.facebook.com/v2.5/me?fields=id,name,email,first_name,last_name";

    options.Events = new OAuthEvents
    {
        OnCreatingTicket = context =>
        {
            if (context.Identity.Claims.All(c => c.Type != "urn:lastname"))
            {
                try
                {
                    var lastName = context.User.Value<string>("last_name");

                    context.Identity.AddClaim(new Claim("urn:lastname", lastName));
                }
                catch { }
            }

            if (context.Identity.Claims.All(c => c.Type != "urn:firstname"))
            {
                try
                {
                    var firstName = context.User.Value<string>("first_name");

                    context.Identity.AddClaim(new Claim("urn:firstname", firstName));
                }
                catch { }
            }

            return Task.FromResult(0);
        }
    };
});

Comme vous pouvez le voir, il faut maintenant passer par la propriété Events, de type IOauthEvents qui, via la propriété OnCreatingTicket, permet d’être notifié lorsque le jeton d’authentification est créé et que les informations sont récupérées depuis le provider.

Pour récupérer les informations depuis les Claims (et éventuellement les afficher dans une vue d’enregistrement), rien de plus simple également:

var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
    return RedirectToAction(nameof(Login));
}
else
{
    var email = info.ExternalPrincipal.FindFirstValue(ClaimTypes.Email);
    var lastName = info.ExternalPrincipal.FindFirstValue("urn:lastname");
    var firstName = info.ExternalPrincipal.FindFirstValue("urn:firstname");
}

Merci à Pinpoint pour son aide et bon code à tous!

 

Happy coding Smile

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus