为什么新的 fb api 2.4 在带有 Identity 和 oauth 2 的 MVC 5 上返回空电子邮件? [英] Why new fb api 2.4 returns null email on MVC 5 with Identity and oauth 2?

查看:21
本文介绍了为什么新的 fb api 2.4 在带有 Identity 和 oauth 2 的 MVC 5 上返回空电子邮件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

过去一切都很完美,直到 fb 将它的 api 升级到 2.4(我之前使用的是 2.3项目).

Everything used to work perfect until fb upgraded it's api to 2.4 (I had 2.3 in my previous project).

今天,当我在 fb 开发人员上添加一个新应用程序时,我通过 api 2.4 获得了它.

Today when I add a new application on fb developers I get it with api 2.4.

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

The problem: Now I get null email from fb (loginInfo.email = null).

当然我检查了用户电子邮件在 fb 个人资料上处于公开状态,

Of course I checked that the user email is in public status on fb profile,

然后我查看了 loginInfo 对象,但没有找到任何其他电子邮件地址.

and I went over the loginInfo object but didn't find any other email address.

我用谷歌搜索但没有找到任何答案.

and I google that but didn't find any answer.

请帮忙..我有点迷茫..

please any help.. I 'm kind of lost..

谢谢,

我的原始代码(适用于 2.3 api):

在 AccountController.cs 中:

In the 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 中:

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

推荐答案

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

Taken from a Katana Thread I devised the following:

更改 FacebookAuthenticationOptions 以包含 BackchannelHttpHandlerUserInformationEndpoint,如下所示.确保包含您想要和需要的字段名称.

Change the FacebookAuthenticationOptions to include BackchannelHttpHandler and UserInformationEndpoint as seen below. Make sure to include the names of the fields you want and need for your implementation.

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.

Then create a custom FacebookBackChannelHandler that will intercept the requests to Facebook and fix the malformed url as needed.

更新:FacebookBackChannelHandler 根据 2017 年 3 月 27 日对 FB api 的更新进行更新.

UPDATE: The FacebookBackChannelHandler is updated based on a 27 Mar 2017 update to the 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 包.

One useful addition would be to check for the version 3.0.1 of the library and throw an exception if and when it changes. That way you'll know if someone upgrades or updates the NuGet package after a fix for this problem has been released.

(更新到构建,在 C# 5 中工作,没有新的特性名称)

(Updated to build, work in C# 5 without new nameof feature)

这篇关于为什么新的 fb api 2.4 在带有 Identity 和 oauth 2 的 MVC 5 上返回空电子邮件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆