首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ASP.NET MVC5在Facebook的身份验证突然失效

ASP.NET MVC5在Facebook的身份验证突然失效
EN

Stack Overflow用户
提问于 2014-03-13 05:40:06
回答 11查看 24.6K关注 0票数 67

更新2017!

当我发布最初的问题时,我遇到的问题与Facebook最近做出的改变没有任何关系,当时他们强迫每个人都使用他们的API版本2.3。有关该特定问题的解决方案,请参阅下面的sammy34的答案。版本2.3的/oauth/access_token端点现在返回JSON,而不是表单编码值

由于历史原因,这里是我最初的问题/问题:

我有一个Facebook应用程序,它通过MVC5和谷歌使用内置的身份验证支持。当我们几个月前构建这个应用程序时,我们遵循了这个教程:http://www.asp.net/mvc/tutorials/mvc-5/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on和一切都工作得很好。

现在,突然之间,Facebook身份验证停止了所有的工作。Google身份验证仍然很有效。

问题描述:我们点击链接使用Facebook连接,我们被重定向到Facebook,在那里,如果我们不想允许我们的Facebook应用程序访问我们的个人资料,我们会得到提示。当我们点击“确定”,我们被重定向回我们的网站,但我们不是登录,而是简单地结束在登录屏幕。

我已经在调试模式下完成了这个过程,并且按照上面提到的教程在我的帐户控制器中获得了这个ActionResult:

// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
    {
        return RedirectToAction("Login");
    }
    ............

在单步执行代码并从Facebook返回时,loginInfo对象始终为空,这会导致用户被重定向回登录。

为了了解幕后实际发生的情况,我安装了Fiddler并监视HTTP流量。我发现的是,在Facebook权限对话框中单击"OK“后,Facebook使用以下URL重定向回我们的应用程序:

https://localhost/signin-facebook?code=<access-token>

这个URL不是一个实际的文件,我猜可能是由这个OWIN框架中内置的某个控制器/处理程序来处理的。最有可能的是,它使用给定的代码连接回Facebook,以查询有关试图登录的用户的信息。现在,问题不是这样做,而是我们被重定向到:

/Account/ExternalLoginCallback?error=access_denied

我相信这正是Facebook正在做的事情,那就是,它不是给我们提供用户数据,而是用这个错误信息重定向我们。

这会导致AuthenticationManager.GetExternalLoginInfoAsync();失败并始终返回NULL。

我完全没有想法了。据我们所知,我们没有做任何改变。

我试着创建一个新的Facebook应用程序,我又试着按照教程操作,但我总是遇到同样的问题。

欢迎任何想法!

更新!

好吧,这快把我逼疯了!现在,我已经手动完成了执行身份验证所需的步骤,当我这样做时,一切都很正常。在使用MVC5 Owin的时候,这到底是为什么不起作用呢?

这是我所做的:

    // Step 1 - Pasted this into a browser, this returns a code
    https://www.facebook.com/dialog/oauth?response_type=code&client_id=619359858118523&redirect_uri=https%3A%2F%2Flocalhost%2Fsignin-facebook&scope=&state=u9R1m4iRI6Td4yACEgO99ETQw9NAos06bZWilJxJrXRn1rh4KEQhfuEVAq52UPnUif-lEHgayyWrsrdlW6t3ghLD8iFGX5S2iUBHotyTqCCQ9lx2Nl091pHPIw1N0JV23sc4wYfOs2YU5smyw9MGhcEuinvTAEql2QhBowR62FfU6PY4lA6m8pD3odI5MwBYOMor3eMLu2qnpEk0GekbtTVWgQnKnH6t1UcC6KcNXYY

I was redirected back to localhost (which I had shut down at this point to avoid being redirected immediately away).  The URL I was redirected to is this:

https://localhost/signin-facebook?code=<code-received-removed-for-obvious-reasons>

Now, I grabbed the code I got and used it in the URL below:

// Step 2 - opened this URL in a browser, and successfully retrieved an access token
https://graph.facebook.com/oauth/access_token?client_id=619359858118523&redirect_uri=https://localhost/signin-facebook&client_secret=<client-secret>&code=<code-from-step-1>

// Step 3 - Now I'm able to query the facebook graph using the access token from step 2!

https://graph.facebook.com/me?access_token=<access-token-from-step-2>

没有错误,一切都很好!那为什么在使用MVC5 Owin的东西时,这不能正常工作呢?很明显,OWin实现出了问题。

EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2014-03-14 06:34:24

好了,我已经有了一个解决问题的办法。

这是我之前在Startup.Auth.cs文件中的代码:

var x = new FacebookAuthenticationOptions();
            //x.Scope.Add("email");
            x.AppId = "1442725269277224";
            x.AppSecret = "<secret>";
            x.Provider = new FacebookAuthenticationProvider()
            {
                OnAuthenticated = async context =>
                {
                        //Get the access token from FB and store it in the database and
                    //use FacebookC# SDK to get more information about the user
                    context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken",context.AccessToken));
                    context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:name", context.Name));
                    context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email));
                }
            };
            x.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
            app.UseFacebookAuthentication(x);

请注意,

x.Scope.Add("email")

行已经被注释掉了,但是稍后我仍然要在OnAuthenticated处理程序中查询电子邮件吗?是的,就是这样。由于某些原因,这种方法在几个星期内运行得无懈可击。

我的解决方案是简单地取消对x.Scope.Add("email");行的注释,以确保scope=email变量出现在对Facebook的初始请求中。

现在一切都像以前一样工作了!

我不明白为什么它以前是这样工作的。我能想到的唯一解释是Facebook改变了他们这一端的一些东西。

票数 9
EN

Stack Overflow用户

发布于 2017-03-28 15:37:51

2017年4月22日更新: Microsoft.Owin.*软件包的版本3.1.0现已推出。如果你在Facebook的API从2017年3月27日改变后有问题,先试试更新后的NuGet包。在我的例子中,他们解决了问题(在我们的生产系统上工作得很好)。

原始答案:

以我为例,我在2017年3月28日醒来时发现,我们的应用程序的Facebook身份验证突然停止工作。我们没有更改应用程序代码中的任何内容。

事实证明,Facebook在2017年3月27日对其图形API进行了“强制升级”,从2.2版升级到2.3版。这些版本的应用编程接口的一个不同之处在于,Facebook端点/oauth/access_token不再使用表单编码的内容主体进行响应,而是使用JSON进行响应。

现在,在Owin中间件中,我们找到了protected override FacebookAuthenticationHandler.AuthenticateCoreAsync()方法,它将响应的正文解析为表单,然后使用解析后的表单中的access_token。不用说,解析后的表单是空的,所以access_token也是空的,从而导致access_denied错误。

为了快速解决这个问题,我们为Facebook Oauth响应创建了一个包装类

public class FacebookOauthResponse
{
    public string access_token { get; set; }
    public string token_type { get; set; }
    public int expires_in { get; set; }
}

然后,在OwinStart中,我们添加了一个自定义的反向通道处理程序...

        app.UseFacebookAuthentication(new FacebookAuthenticationOptions
        {
            AppId = "hidden",
            AppSecret = "hidden",
            BackchannelHttpHandler = new FacebookBackChannelHandler()
        });

...where处理程序定义为:

public class FacebookBackChannelHandler : HttpClientHandler
{
    protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var result = await base.SendAsync(request, cancellationToken);
        if (!request.RequestUri.AbsolutePath.Contains("access_token"))
            return result;

        // For the access token we need to now deal with the fact that the response is now in JSON format, not form values. Owin looks for form values.
        var content = await result.Content.ReadAsStringAsync();
        var facebookOauthResponse = JsonConvert.DeserializeObject<FacebookOauthResponse>(content);

        var outgoingQueryString = HttpUtility.ParseQueryString(string.Empty);
        outgoingQueryString.Add(nameof(facebookOauthResponse.access_token), facebookOauthResponse.access_token);
        outgoingQueryString.Add(nameof(facebookOauthResponse.expires_in), facebookOauthResponse.expires_in + string.Empty);
        outgoingQueryString.Add(nameof(facebookOauthResponse.token_type), facebookOauthResponse.token_type);
        var postdata = outgoingQueryString.ToString();

        var modifiedResult = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(postdata)
        };

        return modifiedResult;
    }
}

基本上,处理程序只是创建一个新的HttpResponseMessage,其中包含来自Facebook JSON响应的等效表单编码信息。请注意,此代码使用流行的Json.Net包。

有了这个自定义处理程序,问题似乎就解决了(尽管我们还没有部署到prod:)。

希望这能拯救今天醒来遇到类似问题的其他人!

此外,如果有人对此有更干净的解决方案,我很想知道!

票数 112
EN

Stack Overflow用户

发布于 2017-03-29 05:49:30

昨天我注意到了这个问题。Facebook不再支持Microsoft.Owin.Security.Facebook版本3.0.1。对我来说,安装3.1.0版是可行的。要更新到3.1.0,请在包管理器控制台中运行命令Install-Package Microsoft.Owin.Security.Facebookhttps://www.nuget.org/packages/Microsoft.Owin.Security.Facebook

票数 27
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22364442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档