ASP.NET MVC5 OWIN Facebook身份验证突然无法正常工作
2017年更新!
我在发布原始问题时遇到的问题与Facebook最近的变化无关,因为Facebook强迫每个人都使用其API版本2.3.有关该特定问题的解决方案,请参阅下面的sammy34的答案. / oauth / access_token端点的2.3版现在返回JSON而不是表单编码值 由于历史原因,这是我原来的问题/问题: 我有一个MVC5 Web应用程序,它使用内置支持通过Facebook和Google进行身份验证.几个月前我们构建这个应用程序时,我们遵循了这个教程: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对象始终为NULL,这会导致用户重定向回登录. 为了理解幕后实际发生的事情,我安装了Fiddler并监控HTTP流量.我发现的是,在Facebook权限对话框中单击“确定”后,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实现显然有问题. 解决方法
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版本.这些版本的API之一的差异似乎是Facebook端点/ oauth / access_token不再响应一个表单编码的内容体,但改为使用JSON. 现在,在Owin中间件中,我们发现受保护的方法覆盖了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() }); …处理程序定义为: 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 :)). 希望拯救别人今天醒来时遇到类似的问题! 此外,如果有人有一个更清洁的解决方案,我很想知道! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 一步步开发自己的博客 .NET版(3、注册登录功能)
- asp.net – 使用.Resx文件获取全局应用程序消息?
- asp.net-mvc – MVC4 Ajax表单URL
- asp.net – 如何在.aspx页面中访问c#变量的值?
- asp.net-mvc – 我可以在’单元测试’时使用断点(如调试时)
- asp.net-mvc-3 – ASP.NET MVC视图模型不绑定在HTTP Post与
- ASP.NET MVC6:以编程方式设置webroot
- 使用ASP.NET开发服务器测试多个域
- asp.net-core – Visual Studio 2017(ASP.NET Core)和Aurel
- asp.net-mvc – 如何将html5属性和值导入mvc HiddenFor
- asp.net – 如何在Visual Studio中生成Web服务的
- asp.net – 为什么加密一个web配置文件?
- asp.net – ScriptManager必须出现在任何需要它的
- asp.net – Web部署和文件夹权限
- asp.net-mvc – T4MVC @ Url.Action(MVC.Control
- asp.net-mvc – ASP.NET Azure 400错误请求不返回
- IIS ASP.NET WebApi在请求同一台服务器时死锁
- asp.net – 用于.NET的HTML Sanitizer
- asp.net – 如何在转发器中每行显示x个项目?
- asp.net-mvc – ScriptBundle中的{version}是什么