Por que o novo fb api 2.4 retorna um e-mail nulo no MVC 5 com Identity e oauth 2?

Tudo funcionou perfeitamente até que fb atualizou sua API para 2.4 (eu tinha 2.3 no meu projeto anterior).

Hoje, quando eu adiciono uma nova aplicação em desenvolvedores fb, eu a obtenho com a API 2.4.

O problema: Agora eu recebo e-mail nulo de fb ( loginInfo.email = null ).

É claro que verifiquei que o email do usuário está em status público no perfil do fb,

e eu fui até o object loginInfo mas não encontrei nenhum outro endereço de email.

e eu google, mas não encontrei nenhuma resposta.

por favor qualquer ajuda .. Eu meio que perdi ..

Obrigado,

Meu código original (que trabalhou em 2.3 api):

No AccountController.cs:

 // // GET: /Account/ExternalLoginCallback [AllowAnonymous] public async Task 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");  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 } } 

No 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); 

Retirado de um Fio Katana , criei o seguinte:

Altere as FacebookAuthenticationOptions para include BackchannelHttpHandler e UserInformationEndpoint como BackchannelHttpHandler abaixo. Certifique-se de include os nomes dos campos que deseja e precisa para sua implementação.

 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" } 

Em seguida, crie um FacebookBackChannelHandler personalizado que interceptará as solicitações para o Facebook e corrija o URL malformado, conforme necessário.

ATUALIZAÇÃO: O FacebookBackChannelHandler é atualizado com base em uma atualização de 27 de março de 2017 na API do FB.

 public class FacebookBackChannelHandler : HttpClientHandler { protected override async System.Threading.Tasks.Task 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(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; } } 

Uma adição útil seria verificar a versão 3.0.1 da biblioteca e lançar uma exceção se e quando ela for alterada. Dessa forma, você saberá se alguém atualizar ou atualizar o pacote NuGet depois que uma correção para esse problema for liberada.

(Atualizado para construir, trabalhar em C # 5 sem novo nome de recurso)

Para mim, este problema foi resolvido atualizando para o Microsoft.Owin.Security.Facebook 3.1.0 e adicionando ’email’ à coleção 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); 

Para resolver isso, você precisa instalar o Facebook SDK a partir dos pacotes do NuGet.

No arquivo StartUp

  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); } } }); 

No controlador ou auxiliar

 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 

Com isso você pode obter o EmailId, First-last Name, Gender.

Você também pode adicionar suas propriedades obrigatórias adicionais nessa string de consulta.

Espero que isso ajude alguém.

Só quero adicionar na resposta de Mike que esta linha

 facebookOptions.Scope.Add("email"); 

ainda precisa ser adicionado depois

 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" } 

E se você já registrou sua conta do facebook no seu site de desenvolvimento, sem “permissão de e-mail”. Depois de alterar o código e tentar novamente, você ainda não receberá o e-mail porque a permissão de e-mail não é concedida ao seu site de desenvolvimento. A maneira que eu faço é ir para https://www.facebook.com/settings?tab=applications , remover meu aplicativo do Facebook e refazer o processo novamente.

Leia o changelog , isso é por design. Você precisa solicitar explicitamente os campos e as bordas que deseja reajustar na resposta:

Campos Declarativos Para tentar melhorar o desempenho em redes móveis, os Nós e Arestas na v2.4 exigem que você solicite explicitamente o (s) campo (s) necessários para suas solicitações GET . Por exemplo, GET /v2.4/me/feed não inclui mais curtidas e comentários por padrão, mas GET /v2.4/me/feed?fields=comments,likes , GET /v2.4/me/feed?fields=comments,likes retornará os dados. Para mais detalhes, consulte os documentos sobre como solicitar campos específicos.

    Intereting Posts