我正在尝试使用FB JavaScript SDK设置一个非常基本的身份验证逻辑流,以在执行操作之前检查用户的登录状态和权限(如果没有权限,则提示用户使用权限登录)。
- 用户在我网站的文本区键入一条消息,发布到他们的Facebook订阅源,然后点击我网站上的"发布到Facebook"按钮
- 响应点击,我用
FB.getLoginStatus
检查用户的登录状态 - 在对
FB.getLoginStatus
的回调中,如果用户未登录,则提示他们登录(FB.login
) - 在对
FB.login
的回调中,我需要确保他们有正确的权限,所以我会调用FB.api('/me/permissions')
——如果他们没有,我会再次提示他们登录(FB.login
)
我遇到的问题是,每当我试图在其他FB方法的回调中调用FB.login
时,浏览器似乎会失去对执行来源(点击)的跟踪,从而阻止弹出窗口。我想知道我是否错过了在检查用户状态后提示用户登录的方法,而浏览器不会误以为这不是用户启动的弹出窗口?
我现在已经回到了只需要先打FB.login()
就可以了。然而,这种方法不希望出现的副作用是,如果用户已经使用权限登录,而我仍在调用FB.login
,则验证弹出窗口将在继续之前立即打开和关闭,尽管这是有效的,但看起来相当bug。
在做某事之前检查用户的登录状态和权限似乎是一个常见的流程,所以我觉得我错过了一些东西。下面是一些示例代码。
<div onclick="onClickPostBtn()">Post to Facebook</div>
<script>
// Callback to click on Post button.
function onClickPostBtn() {
// Check if logged in, prompt to do so if not.
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
checkPermissions(response.authResponse.accessToken);
} else {
FB.login(function(){}, {scope: 'publish_stream'})
}
});
}
// Logged in, check permissions.
function checkPermissions(accessToken) {
FB.api('/me/permissions',
{'access_token': accessToken},
function(response){
// Logged in and authorized for this site.
if (response.data && response.data.length) {
// Parse response object to check for permission here...
if (hasPermission) {
// Logged in with permission, perform some action.
} else {
// Logged in without proper permission, request login with permissions.
FB.login(function(){}, {scope: 'publish_stream'})
}
// Logged in to FB but not authorized for this site.
} else {
FB.login(function(){}, {scope: 'publish_stream'})
}
}
);
}
</script>
我遇到的问题是,每当我试图在其他FB方法的回调中调用FB.login时,浏览器似乎会失去对执行来源(点击)的跟踪,从而阻止弹出窗口。
他实际上并不是"迷失方向"——这是一个完全不同的执行上下文,因为FB方法异步工作。单击发生在一个执行上下文中,该上下文早就不存在了,并且在执行回调函数时已完成。
您可以在页面加载之前检查权限。我想,当用户在你的网站上时,他所获得的权限不太可能发生变化——至少对于一个"正常"用户来说,他不会试图破坏你的应用程序,看看它会有什么反应。(尽管可能有一些用例不能肯定地说这一点。)
如果这导致信息中缺少必要的权限,请致电FB.login,点击按钮请求此权限。在FB.login回调中,如果你想确定的话,你可以再次检查权限-如果权限仍然没有被授予,那么,我建议提醒用户注意这一事实,也许再告诉他为什么有必要这样做-然后他必须再次单击启动整个操作的按钮。
如果权限还可以,那么您可以调用API来实际发布。为了真正确定和安全起见……在API调用的回调中,您可以再次检查成功或错误,如果出现错误,请查明是否是由于缺少权限造成的——如果是,请返回正方,告诉用户权限是必要的,并让他通过单击按钮重新开始整个过程…
我有另一个解决方案,可以更优雅地检查用户是否有
- A) 已登录FB
- B) 正确的权限
简而言之,对于a),您需要"提醒"用户他没有登录,而不是"回调"Fb.login。然后您的页面应该刷新,并在刷新期间处理登录过程。
但是,对于B)权限,您可以使用fb.ui方法(使用display:iframe)请求权限(通过回调),而不是使用fb.login请求权限。使用display:iframe应该可以避免弹出窗口阻塞程序的麻烦。
请参阅以下修改后的代码:
<div onclick="onClickPostBtn()">Post to Facebook</div>
<script>
// Callback to click on Post button.
function onClickPostBtn() {
// Check if logged in, prompt to do so if not.
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
checkPermissions(response.authResponse.accessToken);
} else {
//Don't call FB.login because this results in popup blocker.
//FB.login(function(){}, {scope: 'publish_stream'})
//Instead, just alert user that "YOu are not connected to FB", and then refresh the page (which should theoreticalyl handle the logging aspect)
}
});
}
// Logged in, check permissions.
function checkPermissions(accessToken) {
FB.api('/me/permissions',
{'access_token': accessToken},
function(response){
// Logged in and authorized for this site.
if (response.data && response.data.length) {
// Parse response object to check for permission here...
if (hasPermission) {
// Logged in with permission, perform some action.
} else {
//Don't use FB.login to request permissions. Instead use a FB.ui ({method:'permissions.request'} with "display" set to "iframe"
//FB.login(function(){}, {scope: 'publish_stream'})
FB.ui(
{
method: 'permissions.request',
'perms': 'publish_stream,WHATEVER_PERMISSIONS',
'display': 'iframe' //THIS IS IMPORTANT TO PREVENT POPUP BLOCKER
},
function(response) {
//Do action if permissions add success other wise prompt error adding permissions.
}
}
// Logged in to FB but not authorized for this site.
} else {
//Don't call FB.login because this results in popup blocker.
//FB.login(function(){}, {scope: 'publish_stream'})
//Instead, just alert user that "YOu are not connected to FB", and then refresh the page (which should theoreticalyl handle the logging aspect)
}
}
);
}
</script>