为啥新的 fb api 2.4 在具有身份和 oauth 2 的 MVC 5 上返回空电子邮件?
Posted
技术标签:
【中文标题】为啥新的 fb api 2.4 在具有身份和 oauth 2 的 MVC 5 上返回空电子邮件?【英文标题】:Why new fb api 2.4 returns null email on MVC 5 with Identity and oauth 2?为什么新的 fb api 2.4 在具有身份和 oauth 2 的 MVC 5 上返回空电子邮件? 【发布时间】:2015-11-10 14:54:26 【问题描述】:在 fb 将它的 api 升级到 2.4 之前,一切都正常运行(我之前有 2.3项目)。
今天,当我在 fb 开发人员上添加一个新应用程序时,我使用 api 2.4 获得它。
问题:现在我收到来自 fb (loginInfo.email = null
) 的空电子邮件。
当然,我检查了用户电子邮件在 fb 个人资料中处于公开状态,
我检查了loginInfo
对象,但没有找到任何其他电子邮件地址。
我用谷歌搜索,但没有找到任何答案。
请帮忙..我有点迷路了..
谢谢,
我的原始代码(适用于 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);
【问题讨论】:
我刚刚设置了一个新的 Facebook 应用程序 - 为什么它说 API 版本 2.11?! 2017 年?! 【参考方案1】:取自Katana Thread 我设计了以下内容:
将FacebookAuthenticationOptions
更改为包括BackchannelHttpHandler
和UserInformationEndpoint
,如下所示。确保包含实施所需和需要的字段名称。
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"
然后创建一个自定义FacebookBackChannelHandler
,它将拦截对 Facebook 的请求并根据需要修复格式错误的 url。
更新:FacebookBackChannelHandler
基于 2017 年 3 月 27 日对 FB api 的更新进行更新。
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 版本,并在它发生变化时抛出异常。这样,您将知道在发布此问题的修复程序后是否有人升级或更新了 NuGet 包。
(更新为构建,在 C# 5 中工作,没有新的 nameof 功能)
【讨论】:
tnx,听起来很有趣。我将在下一个项目中检查它。 不客气。我还花了一整天的时间来解决这个问题。发现解决方案后不发布是不道德的。 仍然没有收到电子邮件。 只想补充一点,在 Facebook API 2.7 和 Microsoft.Owin.Security.Facebook 3.0.1 中仍然需要这个解决方案 更新后 3.1.0-rc 邮箱总是空的,这段代码帮我修好了。谢谢!【参考方案2】:对我来说,这个问题通过升级到Microsoft.Owin.Security.Facebook 3.1.0
并将“电子邮件”添加到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);
【讨论】:
比其他一些答案更简单,并且如上所述。我很惊讶通常包含的名称必须被特别指出。 这似乎是最简单和最好的解决方案。请务必添加范围和名称字段。此外,在添加电子邮件字段之前,我还返回了名称字段。如果两者都需要,请务必添加它。 他们登录后如何获取字段值? Options.Fields... 返回错误“FacebookAuthenticationOptions”不包含字段的定义... @niico 获取要显示的字段的定义,将您的 Microsoft.Owin.Security.Facebook 引用更新到版本 3.1.0(您可能在 3.0.1 上)【参考方案3】:要解决此问题,您需要从 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、First-last Name、Gender。
您还可以在该查询字符串中添加其他必需的属性。
希望这会对某人有所帮助。
【讨论】:
谢谢!这也解决了我的问题。如果您还想从动态 myInfo 中获取值,那么有一种简单的方法可以做到这一点:myInfo.email(而不是电子邮件,它可以是性别、名字等)【参考方案4】:只是想在迈克的回答中添加这一行
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 应用程序,然后再次重做该过程。
【讨论】:
是的,如上所述。这是完整的解决方案。【参考方案5】: 将 Microsoft.Owin 升级到 3.0.1(安装包 Microsoft.Owin.Security.OAuth) 在 Startup.Auth.cs 添加 facebookOptions.UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email";【讨论】:
【参考方案6】:阅读changelog,这是设计使然。您需要在响应中明确请求要重新调整的字段和边:
声明性字段 为了尝试提高移动网络的性能, v2.4 中的节点和边缘要求您明确请求
GET
请求所需的字段。比如GET /v2.4/me/feed
默认不再包含likes和cmets,而是GET /v2.4/me/feed?fields=comments,likes
将返回数据。更多 有关如何请求特定字段的详细信息,请参阅docs。
【讨论】:
是的,我知道,但不知道如何在C#代码上修改外部facebook oauth-2中的GET前缀url。 对我有用的唯一方法是按照以下帖子安装“Facebook SDK for .NET”:first post,second post。但是,我希望我能在不安装任何额外软件包的情况下找到解决方案。 @Dudi,Mike Trionfo 的回答效果很好。我只是对其进行了修改,以不修复特定的 API 版本(UserInformationEndpoint = "https://graph.facebook.com/me?fields=id,name,email")。以上是关于为啥新的 fb api 2.4 在具有身份和 oauth 2 的 MVC 5 上返回空电子邮件?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 上获取 FB Chat 的 API 密钥和会话密钥和会话密钥