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

Dud*_*udi 46 c# facebook facebook-graph-api asp.net-mvc-5 asp.net-identity-2

一切都习以为常,直到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
    }
}
Run Code Online (Sandbox Code Playgroud)

在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);
Run Code Online (Sandbox Code Playgroud)

Mik*_*nfo 81

取自Katana线程我设计了以下内容:

更改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"
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个自定义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; }
}
Run Code Online (Sandbox Code Playgroud)

一个有用的补充是检查库的3.0.1版本,并在它发生变化时抛出异常.这样,您就可以知道在解决此问题的修复程序之后是否有人升级或更新了NuGet包.

(更新为构建,在没有新名称功能的情况下使用C#5)


Iss*_*sac 23

对我来说,通过升级并向集合中Microsoft.Owin.Security.Facebook 3.1.0添加"email"来解决此问题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);
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是最简单和最好的解决方案.请务必添加范围和名称字段.此外,我收到了名称字段,直到我添加了电子邮件字段.如果您需要两者,请务必添加它. (2认同)

小智 20

要解决此问题,您需要从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);
                    }
                }
            });
Run Code Online (Sandbox Code Playgroud)

在控制器或助手

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
Run Code Online (Sandbox Code Playgroud)

有了这个,您可以获得EmailId,姓氏,性别.

您还可以在该查询字符串中添加其他必需属性.

希望这会对某人有所帮助.

  • 谢谢!这也解决了我的问题.如果你还想从动态myInfo获取值,那么有一种简单的方法可以做到这一点:myInfo.email(而不是电子邮件,它可以是gender,first_name等) (2认同)

pai*_*boo 13

只想在迈克的答案上加上这一行

facebookOptions.Scope.Add("email");
Run Code Online (Sandbox Code Playgroud)

仍然需要在之后添加

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"
}
Run Code Online (Sandbox Code Playgroud)

如果您已经将您的Facebook帐户注册到您的开发网站而没有"电子邮件许可".更改代码并再次尝试后,您仍然无法收到电子邮件,因为您的开发者网站未授予电子邮件权限.我的方法是访问https://www.facebook.com/settings?tab=applications,删除我的Facebook应用程序,然后重新进行重做.


ifa*_*our 1

阅读变更日志,这是设计使然。您需要明确请求要在响应中重新调整的字段和边缘:

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