为什么新的fb api 2.4在Identity和oauth 2上的MVC 5上返回null电子邮件?

所有的东西都用来完美的工作,直到fb把它的api升级到2.4 (我在以前的项目中我的版本是2.3 )。

今天当我在fb开发人员上添加一个新的应用程序时,我使用api 2.4。

问题:现在我从fb( loginInfo.email = null )收到空电子邮件。

当然,我检查用户的电子邮件是在公共状态fbconfiguration文件,

我去了loginInfo对象,但没有find任何其他的电子邮件地址。

我谷歌,但没有find任何答案。

请任何帮助..我有点失落..

谢谢,

我的原始代码(在2.3 api上工作):

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

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

采取从武士刀线我devise了以下内容:

FacebookAuthenticationOptions更改为包含BackchannelHttpHandlerUserInformationEndpoint ,如下所示。 确保包含您想要的和实施所需的字段的名称。

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

然后创build一个自定义FacebookBackChannelHandler ,将拦截到Facebook的请求,并根据需要修复格式不正确的url。

更新: FacebookBackChannelHandler基于FB api 2017年3月27日更新进行更新。

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

一个有用的补充是检查库的版本3.0.1,并且如果和当它改变时抛出一个exception。 这样你会知道是否有人升级或更新NuGet软件包后,解决这个问题已被释放。

(已更新为构build,使用C#5而不使用新function)

要解决这个问题,你需要从NuGet包安装Facebook SDK。

在启动文件

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

在控制器或助手

 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 

有了这个,你可以得到EmailId,名字,性别。

您还可以在查询string中添加其他必需的属性。

希望这会帮助别人。

对于我来说,这个问题是通过升级到Microsoft.Owin.Security.Facebook 3.1.0并向Fields集合添加“email”来解决的:

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

只是想在Mike的回答中加上这一行

 facebookOptions.Scope.Add("email"); 

仍然需要添加之后

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

如果你已经注册你的Facebook帐户到您的开发网站没有“电子邮件许可”。 更改代码并再次尝试后,您仍然不会收到电子邮件,因为电子邮件许可权未授予您的开发者网站。 我的方式是去https://www.facebook.com/settings?tab=applications ,删除我的Facebook应用程序,并重新进行过程。

阅读更新日志 ,这是devise。 您需要明确地请求您在响应中重新调用的字段和边缘:

声明性字段为了尝试提高移动networking的性能,v2.4中的节点和边缘要求您显式地请求您的GET请求所需的字段。 例如, GET /v2.4/me/feed默认不再包含喜欢和评论,但GET /v2.4/me/feed?fields=comments,likes将返回数据。 有关更多详细信息,请参阅有关如何请求特定字段的文档 。