web-dev-qa-db-fra.com

Pourquoi le nouveau fb api 2.4 renvoie un e-mail nul sur MVC 5 avec identité et oauth 2?

Tout fonctionnait parfaitement jusqu'à ce que fb soit mis à niveau, c'est une API pour 2.4 (J'avais 2.3 dans mon projet précédent).

Aujourd'hui, lorsque j'ajoute une nouvelle application sur les développeurs fb, je l'obtiens avec l'api 2.4.

Le problème: maintenant je reçois un e-mail nul de fb (loginInfo.email = null).

Bien sûr, j'ai vérifié que l'e-mail de l'utilisateur est public sur le profil fb,

et j'ai parcouru l'objet loginInfo mais je n'ai trouvé aucune autre adresse e-mail.

et je google ça mais je n'ai trouvé aucune réponse.

s'il vous plaît toute aide .. je suis un peu perdu ..

Merci,

Mon code d'origine (qui fonctionnait sur 2.3 api):

Dans le AccountController.cs:

//
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
    {
        return RedirectToAction("Login");
    }
    //A way to get fb details about the log-in user: 
    //var firstNameClaim = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:first_name");  <--worked only on 2.3
    //var firstNameClaim = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:name"); <--works on 2.4 api

    // Sign in the user with this external login provider if the user already has a login
    var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
        case SignInStatus.Failure:
        default:
            // If the user does not have an account, then Prompt the user to create an account
            ViewBag.ReturnUrl = returnUrl;
            ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
            return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });  //<---DOESN'T WORK. loginInfo.Email IS NULL
    }
}

Dans le Startup.Auth.cs:

    Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions fbOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
    {
        AppId = System.Configuration.ConfigurationManager.AppSettings.Get("FacebookAppId"),
        AppSecret = System.Configuration.ConfigurationManager.AppSettings.Get("FacebookAppSecret"),
    };
    fbOptions.Scope.Add("email");
    fbOptions.Provider = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationProvider()
    {
        OnAuthenticated = (context) =>
        {
            context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
            foreach (var claim in context.User)
            {
                var claimType = string.Format("urn:facebook:{0}", claim.Key);
                string claimValue = claim.Value.ToString();
                if (!context.Identity.HasClaim(claimType, claimValue))
                    context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Facebook"));

            }
            return System.Threading.Tasks.Task.FromResult(0);
        }
    };
    fbOptions.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
    app.UseFacebookAuthentication(fbOptions);
46
Dudi

Tiré d'un Katana Thread J'ai conçu ce qui suit:

Modifiez FacebookAuthenticationOptions pour inclure BackchannelHttpHandler et UserInformationEndpoint comme indiqué ci-dessous. Assurez-vous d'inclure les noms des champs que vous souhaitez et dont vous avez besoin pour votre implémentation.

var facebookOptions = new FacebookAuthenticationOptions()
{
    AppId = "*",
    AppSecret = "*",
    BackchannelHttpHandler = new FacebookBackChannelHandler(),
    UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email,first_name,last_name"
}

Créez ensuite un FacebookBackChannelHandler personnalisé qui interceptera les demandes à Facebook et corrigera l'url malformée si nécessaire.

MISE À JOUR: FacebookBackChannelHandler est mis à jour sur la base d'une mise à jour du 27 mars 2017 de l'API FB.

public class FacebookBackChannelHandler : HttpClientHandler
{
    protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
        {
            request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token"));
        }

        var result = await base.SendAsync(request, cancellationToken);
        if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
        {
            return result;
        }

        var content = await result.Content.ReadAsStringAsync();
        var facebookOauthResponse = JsonConvert.DeserializeObject<FacebookOauthResponse>(content);

        var outgoingQueryString = HttpUtility.ParseQueryString(string.Empty);
        outgoingQueryString.Add("access_token", facebookOauthResponse.access_token);
        outgoingQueryString.Add("expires_in", facebookOauthResponse.expires_in + string.Empty);
        outgoingQueryString.Add("token_type", facebookOauthResponse.token_type);
        var postdata = outgoingQueryString.ToString();

        var modifiedResult = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(postdata)
        };

        return modifiedResult;
    }
}

public class FacebookOauthResponse
{
    public string access_token { get; set; }
    public string token_type { get; set; }
    public int expires_in { get; set; }
}

Un ajout utile serait de vérifier la version 3.0.1 de la bibliothèque et de lever une exception si et quand elle change. De cette façon, vous saurez si quelqu'un met à niveau ou met à jour le package NuGet après la publication d'un correctif pour ce problème.

(Mise à jour pour construire, travailler en C # 5 sans nouvelle fonctionnalité nameof)

81
Mike Trionfo

Pour moi, ce problème a été résolu en passant à Microsoft.Owin.Security.Facebook 3.1.0 et en ajoutant 'email' à la collection Fields:

var options = new FacebookAuthenticationOptions
{
    AppId = "-------",
    AppSecret = "------",    
};
options.Scope.Add("public_profile");
options.Scope.Add("email");

//add this for facebook to actually return the email and name
options.Fields.Add("email");
options.Fields.Add("name");

app.UseFacebookAuthentication(options);
23
Issac

Pour résoudre ce problème, vous devez installer le SDK Facebook à partir des packages NuGet.

Dans le fichier de démarrage

 app.UseFacebookAuthentication(new FacebookAuthenticationOptions
            {
                AppId = "XXXXXXXXXX",
                AppSecret = "XXXXXXXXXX",
                Scope = { "email" },
                Provider = new FacebookAuthenticationProvider
                {
                    OnAuthenticated = context =>
                    {
                        context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
                        return Task.FromResult(true);
                    }
                }
            });

Dans le contrôleur ou l'aide

var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
var accessToken = identity.FindFirstValue("FacebookAccessToken");
var fb = new FacebookClient(accessToken);
dynamic myInfo = fb.Get("/me?fields=email,first_name,last_name,gender"); // specify the email field

Avec cela, vous pouvez obtenir l'EmailId, le prénom, le sexe.

Vous pouvez également ajouter vos propriétés supplémentaires requises dans cette chaîne de requête.

J'espère que cela aidera quelqu'un.

20
Palak Patel

Je veux juste ajouter à la réponse de Mike que cette ligne

facebookOptions.Scope.Add("email");

doit encore être ajouté après

var facebookOptions = new FacebookAuthenticationOptions()
{
    AppId = "*",
    AppSecret = "*",
    BackchannelHttpHandler = new FacebookBackChannelHandler(),
    UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email,first_name,last_name,location"
}

Et si vous avez déjà enregistré votre compte Facebook sur votre site Web de développement sans "autorisation par e-mail". Après avoir modifié le code et réessayé, vous ne recevrez toujours pas l'e-mail car l'autorisation e-mail n'est pas accordée à votre site Web de développement. La façon dont je le fais est d'aller sur https://www.facebook.com/settings?tab=applications , de supprimer mon application Facebook et de recommencer le processus.

13
paibamboo
3
Artur Edilyan

Lisez le changelog , c'est par conception. Vous devez explicitement demander les champs et les bords que vous souhaitez retoucher dans la réponse:

Champs déclaratifs Pour essayer d'améliorer les performances sur les réseaux mobiles, Nodes and Edges dans v2.4 nécessite que vous demandiez explicitement le ou les champs dont vous avez besoin pour votre GET requêtes. Par exemple, GET /v2.4/me/feed n'inclut plus les likes et les commentaires par défaut, mais GET /v2.4/me/feed?fields=comments,likes renverra les données. Pour plus de détails, voir docs sur la façon de demander des champs spécifiques.

1
ifaour