Facebook 回调已开始将 #_=_
哈希下划线附加到返回 URL
有谁知道为什么?解决办法是什么?
#_=_
就位,然后即使你对你真正想做的地方做了一个 Response.Redirect
,浏览器维护散列,这就是为什么只有下面建议的客户端解决方法才有效。
通过 Facebook's Platform Updates:
会话重定向行为的变化 本周,当该字段留空时,我们开始将片段#____=____ 添加到 redirect_uri。请确保您的应用可以处理此行为。
为防止这种情况,请在您的登录 url 请求中设置 redirect_uri,如下所示:(使用 Facebook php-sdk)
$facebook->getLoginUrl(array('redirect_uri' => $_SERVER['SCRIPT_URI'],'scope' => 'user_about_me'));
更新
以上正是 documentation 所说的解决这个问题。但是,Facebook 记录的解决方案不起作用。请考虑在 Facebook Platform Updates blog post 上发表评论并关注 this bug 以获得更好的答案。在此之前,请将以下内容添加到您的 head 标签中以解决此问题:
<script type="text/javascript">
if (window.location.hash && window.location.hash == '#_=_') {
window.location.hash = '';
}
</script>
或者更详细的替代方案(感谢 niftylettuce):
<script type="text/javascript">
if (window.location.hash && window.location.hash == '#_=_') {
if (window.history && history.pushState) {
window.history.pushState("", document.title, window.location.pathname);
} else {
// Prevent scrolling by storing the page's current scroll offset
var scroll = {
top: document.body.scrollTop,
left: document.body.scrollLeft
};
window.location.hash = '';
// Restore the scroll offset, should be flicker free
document.body.scrollTop = scroll.top;
document.body.scrollLeft = scroll.left;
}
}
</script>
TL;博士
if (window.location.hash === "#_=_"){
history.replaceState
? history.replaceState(null, null, window.location.href.split("#")[0])
: window.location.hash = "";
}
带有分步说明的完整版
// Test for the ugliness.
if (window.location.hash === "#_=_"){
// Check if the browser supports history.replaceState.
if (history.replaceState) {
// Keep the exact URL up to the hash.
var cleanHref = window.location.href.split("#")[0];
// Replace the URL in the address bar without messing with the back button.
history.replaceState(null, null, cleanHref);
} else {
// Well, you're on an old browser, we can get rid of the _=_ but not the #.
window.location.hash = "";
}
}
一步步:
如果片段是#_=_,我们只会进入代码块。检查浏览器是否支持 HTML5 window.replaceState 方法。通过拆分 # 并仅获取第一部分来清理 URL。告诉历史用干净的 URL 替换当前页面状态。这会修改当前的历史条目,而不是创建一个新条目。这意味着后退和前进按钮将按照您想要的方式工作。 ;-) 如果浏览器不支持超棒的 HTML 5 历史记录方法,那么只需通过将哈希设置为空字符串来尽可能地清理 URL。这是一个糟糕的回退,因为它仍然留下一个尾随散列 (example.com/#),并且它还添加了一个历史条目,因此后退按钮将带您回到 #_-_。
详细了解 history.replaceState
。
详细了解 window.location
。
出于安全原因,这是由 Facebook 设计实现的。以下是 Facebook 团队成员 Eric Osgood 的解释:
这已被标记为“设计使然”,因为它可以防止潜在的安全漏洞。一些浏览器会将 URL 中的哈希片段附加到它们被重定向到的新 URL 的末尾(如果该新 URL 本身没有哈希片段)。例如,如果 example1.com 返回到 example2.com 的重定向,则转到 example1.com#abc 的浏览器将转到 example2.com#abc,并且 example2 上的脚本可以访问来自 example1.com 的哈希片段内容.com。由于可以将一个身份验证流重定向到另一个,因此可以使来自一个应用程序的敏感身份验证数据可供另一个应用程序访问。通过将新的哈希片段附加到重定向 URL 以防止这种浏览器行为,可以缓解这种情况。如果结果 URL 的美学或客户端行为受到关注,则可以使用 window.location.hash(甚至您自己的服务器端重定向)来删除有问题的字符。
来源:https://developers.facebook.com/bugs/318390728250352/
#
而没有其他任何东西,漏洞仍然存在减轻了,但不,他们不得不放一些更奇怪的东西,需要肮脏的变通办法
如果您想从 url 中删除剩余的“#”
$(window).on('load', function(e){
if (window.location.hash == '#_=_') {
window.location.hash = ''; // for older browsers, leaves a # behind
history.pushState('', document.title, window.location.pathname); // nice and clean
e.preventDefault(); // no page reload
}
})
e
的 onWindowReady 事件侦听器。
不知道他们为什么要这样做,但是,您可以通过重置页面顶部的哈希来解决这个问题:
if (window.location.hash == "#_=_")
window.location.hash = "";
您还可以在 Facebook 回调的 redirect_uri
参数上指定您自己的哈希,这在某些情况下可能会有所帮助,例如 /api/account/callback#home
。当您被重定向回来时,如果您使用的是backbone.js或类似的东西(不确定jquery mobile),它至少是一个与已知路由相对应的哈希。
非常烦人,特别是对于解析 URI 而不仅仅是读取 $_GET 的应用程序...这是我拼凑的黑客...享受!
<html xmlns:fb='http://www.facebook.com/2008/fbml'>
<head>
<script type="text/javascript">
// Get rid of the Facebook residue hash in the URI
// Must be done in JS cuz hash only exists client-side
// IE and Chrome version of the hack
if (String(window.location.hash).substring(0,1) == "#") {
window.location.hash = "";
window.location.href=window.location.href.slice(0, -1);
}
// Firefox version of the hack
if (String(location.hash).substring(0,1) == "#") {
location.hash = "";
location.href=location.href.substring(0,location.href.length-3);
}
</script>
</head>
<body>
URI should be clean
</body>
</html>
如果您使用带有 hashbang (/#!/) URL 的 JS 框架,例如 Angular,这可能会成为一个严重的问题。事实上,Angular 会认为带有非 hashbang 片段的 URL 无效并抛出错误:
Error: Invalid url "http://example.com/#_=_", missing hash prefix "#!".
如果您在这种情况下(并重定向到您的域根目录),而不是这样做:
window.location.hash = ''; // goes to /#, which is no better
只需这样做:
window.location.hash = '!'; // goes to /#!, which allows Angular to take care of the rest
我看不出这个问题与 facebook AJAX 有什么关系。事实上,禁用 JavaScript 和纯粹基于重定向的登录也会出现此问题。
与 facebook 的示例交换:
1. GET <https://www.facebook.com/dialog/oauth?client_id=MY_APP_ID&scope=email&redirect_uri=MY_REDIRECT_URL> RESPONSE 302 Found Location: <https://www.facebook.com/connect/uiserver.php?[...]>
2. GET <https://www.facebook.com/connect/uiserver.php?[...]> RESPONSE 302 Found MY_REDIRECT_URL?code=FB_CODE#_
3. GET MY_REDIRECT_URL?code=FB_CODE#_
对我来说也只发生在 Firefox 上。
将此添加到我的重定向页面解决了我的问题......
if (window.location.href.indexOf('#_=_') > 0) {
window.location = window.location.href.replace(/#.*/, '');
}
使用 angular 和 angular ui 路由器,您可以解决此问题
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
// Make a trailing slash optional for all routes
// - Note: You'll need to specify all urls with a trailing slash if you use this method.
$urlRouterProvider.rule(function ($injector, $location) {
/***
Angular misbehaves when the URL contains a "#_=_" hash.
From Facebook:
Change in Session Redirect Behavior
This week, we started adding a fragment #_=_ to the redirect_uri when this field is left blank.
Please ensure that your app can handle this behavior.
Fix:
http://stackoverflow.com/questions/7131909/facebook-callback-appends-to-return-url#answer-7297873
***/
if ($location.hash() === '_=_'){
$location.hash(null);
}
var path = $location.url();
// check to see if the path already has a slash where it should be
if (path[path.length - 1] === '/' || path.indexOf('/?') > -1) {
return;
}
else if (path.indexOf('?') > -1) {
$location.replace().path(path.replace('?', '/?'));
}
else {
$location.replace().path(path + '/');
}
});
// etc ...
});
});
如果您使用的是 vue-router,则可以附加到路由列表:
{
path: '/_=_',
redirect: '/', // <-- or other default route
},
对我来说,我将 JavaScript 重定向到另一个页面以摆脱 #_=_
。下面的想法应该有效。 :)
function redirect($url){
echo "<script>window.location.href='{$url}?{$_SERVER["QUERY_STRING"]}'</script>";
}
一个对我有用的解决方法(使用 Backbone.js)是在传递给 Facebook 的重定向 URL 的末尾添加“#/”。 Facebook 将保留提供的片段,而不是附加自己的“_=_”。
返回时,Backbone 将删除“#/”部分。对于 AngularJS,附加“#!”返回 URL 应该可以工作。
请注意,大多数浏览器在重定向(通过 HTTP 状态代码 300、301、302 和 303)时会保留原始 URL 的片段标识符,除非重定向 URL 也具有片段标识符。这个seems to be recommended behaviour。
如果您使用将用户重定向到其他地方的处理程序脚本,您可以在此处将“#”附加到重定向 URL 以将片段标识符替换为空字符串。
我知道这个回复很晚,但如果你使用的是 passportjs,你可能想看看这个。
return (req, res, next) => {
console.log(req.originalUrl);
next();
};
我已经编写了这个中间件并将其应用于表达服务器实例,并且我得到的原始 URL 没有 "#_=_"
。看起来当我们将 passporJS 的实例作为中间件应用到服务器实例时,它不使用这些字符,但只在浏览器的地址栏上可见。
我也使用这个来删除“#”符号。
<script type="text/javascript">
if (window.location.hash && window.location.hash == '#_=_') {
window.location.href = window.location.href.split('#_=_')[0];
}
</script>
对于 PHP SDK 用户
我只是通过在转发之前删除多余的部分来解决问题。
$loginURL = $helper->getLoginUrl($redirectURL, $fbPermissions);
$loginURL = str_replace("#_=_", "", $loginURL);
header("Location: " . $loginURL);
这将删除附加的字符到您的网址
<script type="text/javascript">
var idx=window.location.toString().indexOf("#_=_");
if (idx > 0) {
window.location = window.location.toString().substring(0, idx);
}
</script>
使用 Angular 2 (RC5) 和基于哈希的路由,我这样做:
const appRoutes: Routes = [
...
{path: '_', redirectTo: '/facebookLoginSuccess'},
...
]
和
export const routing = RouterModule.forRoot(appRoutes, { useHash: true });
据我了解,路由中的 =
字符被解释为可选路由参数定义的一部分(参见 https://angular.io/docs/ts/latest/guide/router.html#!#optional-route-parameters),因此不参与路由匹配。
删除“#_=_”(PHP)的最简单和干净的解决方案:
而不是“标题(“位置:xxx.php”);”使用 "echo ("location.href = 'xxx.php';");"
对于那些正在寻找简单答案的人只需添加这个,它对我有用
if (window.location.hash === "#_=_"){
history.replaceState
? history.replaceState(null, null, window.location.href.split("#")[0])
: window.location.hash = "";
}
查看 Paul Schwarz 的完整答案
https://stackoverflow.com/a/18305085/2694806
不定期副业成功案例分享