如要在不使用我们的 SDK 的情况下为网页或桌面应用实施基于浏览器的登录,例如在原生桌面应用(如 Windows 8)的网页视图中,或需实施完全使用服务器端代码的登录流程,您可以使用浏览器重定向来构建自己的登录流程。本指南将介绍登录流程的每个步骤,并展示如何在不使用我们的 SDK 的情况下实施每个步骤:
如要在桌面应用中使用 Facebook 登录,您需要在应用中嵌入网页浏览器(有时称为“网页视图”),才能执行登录流程。
使用我们的 SDK 的应用可以通过内置函数检查用户是否已登录。所有其他应用必须自行创建存储用户已登录状态的方式,并在该指标不存在时假定用户已退出,然后继续执行流程。如果用户退出,您的应用应适时将其重定向至登录对话框,例如在用户点击“登录”按钮时。
无论用户是没有登录您的应用还是没有登录 Facebook,您都可以使用登录对话框来提示他们登录。如果用户未登录 Facebook,系统将提示他们登录 Facebook,然后再登录您的应用。系统会自动检测这种情况,所以您无需执行任何额外操作即可启用此行为。
应用必须启动指向端点的重定向,该端点将显示登录对话框:
https://www.facebook.com/v21.0
/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&state={state-param}
该端点包含以下必要参数:
client_id
。应用面板中显示的应用编号。redirect_uri
。重定向登录的用户时指向的网址。该网址将捕获来自登录对话框的响应。如果您在桌面应用的网页视图中使用该网址,则必须将其设置为 https://www.facebook.com/connect/login_success.html
。您可以在应用面板中确认是否已为您的应用设置该网址。在应用面板左侧导航菜单的产品下点击 Facebook 登录,然后点击设置。在客户端 OAuth 设置部分验证有效的 OAuth 重定向 URI。state
。应用创建的字符串值,用于维持请求和回调之间的状态。为防止跨站请求伪造攻击,您应当使用此参数,系统会在重定向 URI 中将其原样传回给您。例如,如果您的登录请求如下所示:
https://www.facebook.com/v21.0
/dialog/oauth?
client_id={app-id}
&redirect_uri={"https://www.domain.com/login"}
&state={"{st=state123abc,ds=123456789}"}
则您的重定向 URI 将通过下列代码调用:
https://www.domain.com/login?state="{st=state123abc,ds=123456789}"
另外还有以下可选参数:
response_type
。确定重定向回应用时所包含的响应数据是网址参数形式还是网址片段形式。请参阅验证身份部分,选择应用应使用的参数类型。这些参数的类型可为以下其中一种:
code
。所包含的响应数据为网址参数形式,且包含 code
参数(每个登录请求独有的加密字符串)。如果未指定此参数,则此为默认行为。当服务器处理口令时,此行为尤为实用。token
。所包含的响应数据为网址片段形式,且包含访问口令。桌面应用必须为 response_type
使用此设置。当客户端处理口令时,此行为尤为实用。code%20token
。所包含的响应数据为网址片段形式,且包含访问口令和 code
参数。granted_scopes
。返回逗号分隔列表,其中包含用户在登录时授予应用的所有权限。可与其他 response_type
值合并。与 token
合并时,所包含的响应数据为网址片段形式;与其他值合并时,所包含的响应数据则为网址参数形式。 scope
。逗号或空格分隔列表,其中包含要向应用用户请求的权限。如果您要为 Windows 应用构建登录,可以使用项目包安全识别符作为 redirect_uri
。通过调用 WebAuthenticationBroker.AuthenticateAsync
触发登录对话框,并使用登录对话框端点作为 requestUri。以下是 JavaScript 中的示例:
var requestUri = new Windows.Foundation.Uri(
"https://www.facebook.com/v21.0
/dialog/oauth?
client_id={app-id}
&display=popup
&response_type=token
&redirect_uri=ms-app://{package-security-identifier}");
Windows.Security.Authentication.Web.WebAuthenticationBroker.authenticateAsync(
options,
requestUri)
.done(function (result) {
// Handle the response from the Login Dialog
}
);
上述示例会向应用返回控制流程,并在成功时附带访问口令,失败时提示错误。
在登录流程的这一阶段,用户会看到登录对话框,并可选择取消登录或允许应用访问其数据。
如果应用用户在登录对话框中选择“确定”,则用户将授予公开资料、好友名单的访问权限,以及应用请求的所有其他权限。
任何情况下,浏览器都会回复应用,并提供响应数据,表明用户已连接还是已取消。当应用使用上述重定向方法时,应用返回的 redirect_uri
将附加必须予以捕获的网址参数或网址片段(根据所选的 response_type
)。
在网页应用中可使用多种代码语言组合,因此本指南不提供具体示例。不过,大多数现代语言都能进行网址解析,如下所示:
客户端 JavaScript 可以捕获网址片段(例如 jQuery BBQ),但网址参数可由客户端和服务器端的代码捕获(例如 PHP 的 $_GET
、jQuery BBQ 中的 jQuery.deparam
、Node.js 中的 querystring.parse
,或 Python 中的 urlparse
)。Microsoft 提供了 Windows 8 应用的指南和代码示例,说明如何连接到“网络运营商”(在本示例中为 Facebook)。
使用桌面应用登录时,Facebook 会将用户重定向至上述 redirect_uri
,并在 URI 片段中放置访问口令及其他一些元数据(例如口令过期时间):
https://www.facebook.com/connect/login_success.html# access_token=ACCESS_TOKEN...
应用需要检测该重定向,然后使用您所用的操作系统及开发框架提供的机制,读取 URI 中的访问口令。之后,您可以直接跳至检查访问口令步骤。
如果应用用户不接受登录对话框并点击了“取消”,则系统会将其重定向至以下位置:
YOUR_REDIRECT_URI? error_reason=user_denied &error=access_denied &error_description=Permissions+error.
请参阅处理缺失的权限,详细了解用户拒绝登录时应用应如何操作。
由于该重定向流程涉及浏览器从登录对话框重定向至应用中的网址,因此流量可以直接访问此包含片段或参数的网址。如果应用假定这些是有效参数,则会把内含的数据用于具有潜在恶意的用途。因此,在为用户生成访问口令前,应用应首先确认当前应用用户与响应数据所针对的用户是同一人。完成身份验证的方式有多种,具体取决于上述接收到的 response_type
:
code
后,需要使用端点将其交换为访问口令。由于调用涉及到应用密钥,因此需采用服务器到服务器的形式。(应用密钥绝不能出现在客户端代码中。)token
后,需要对其进行验证。您应向检查端点发出 API 调用,该调用会显示口令为谁生成,以及由哪个应用生成。由于此 API 调用需要使用应用访问口令,因此请勿从客户端执行此调用,您应从服务器端执行此调用,以便安全存储应用密钥。code
和 token
,则上述两个步骤均需执行。请注意,您也可以生成自己的 state
参数,并将其用于登录请求,以便提供 CSRF 保护。
如要获取访问口令,请向以下 OAuth 端点发出 HTTP GET 请求:
GET https://graph.facebook.com/v21.0
/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
该端点包含部分必要参数:
client_id
。应用编号redirect_uri
。此为必要参数,且必须与开始 OAuth 登录流程时使用的原始 request_uri
相同。client_secret
。唯一的应用密钥,显示在应用面板中。切勿将此应用密钥放入可能被反编译的客户端代码或二进制文件中。由于密钥是应用和所有用户的安全核心,因此保持密钥的绝对机密至关重要。code
。从上述登录对话框重定向接收的参数。请注意:从 2.3 版本开始,此端点会返回正确的 JSON 响应。如果调用未指定版本,则会默认使用最早的可用版本。
响应
您从该端点收到的响应将以 JSON 格式返回,如果成功,将如下方所示:
{ "access_token": {access-token}, "token_type": {type}, "expires_in": {seconds-til-expiration} }
如果失败,您将收到一条说明情况的错误消息。
无论使用 code
还是 token
作为登录对话框的 response_type
,应用都将收到访问口令。您可以使用图谱 API 端点自动检查这些口令:
GET graph.facebook.com/debug_token? input_token={token-to-inspect} &access_token={app-token-or-admin-token}
该端点使用以下参数:
input_token
。您需要检查的口令。access_token
。应用访问口令,或者应用开发者的访问口令。API 调用响应为 JSON 数组,其中包含所检查口令的相关数据。例如:
{ "data": { "app_id": 138483919580948, "type": "USER", "application": "Social Cafe", "expires_at": 1352419328, "is_valid": true, "issued_at": 1347235328, "metadata": { "sso": "iphone-safari" }, "scopes": [ "email", "publish_actions" ], "user_id": "1207059" } }
app_id
和 user_id
字段有助应用确认访问口令是否对用户和您的应用有效。如需其他字段的完整描述,请参阅获取访问口令相关信息的指南。
调用/me/permissions
连线,即可检索特定用户已授予或拒绝的权限列表。应用可调用此连线,检查其无法针对特定用户使用的已请求权限。
Facebook 登录允许用户拒绝向应用分享某些权限。登录对话框包括如下所示的页面:
public_profile
权限始终为必要权限,而且由于无法禁用此权限,因此选项按钮会显示为灰色。
但在此示例中,如果用户取消勾选 user_likes
(赞),则在检查 /me/permissions
以了解已授予的权限时,会生成以下结果:
{ "data": [ { "permission":"public_profile", "status":"granted" }, { "permission":"user_likes", "status":"declined" } ] }
请注意,user_likes
的状态是遭拒,而不是获授权。
您可以再次请求用户向应用授予已拒绝的权限。您应该设置一个说明页面,告知用户应该授予相关权限的原因,然后重新请求。但若您像之前一样调用登录对话框,则系统不会请求该权限。
这是因为用户一旦拒绝授予某权限,除非您明确告知登录对话框您正在重新请求已拒绝的权限,否则登录对话框不会重新请求该权限。
只需在登录对话框网址中添加 auth_type=rerequest
参数即可:
https://www.facebook.com/v21.0
/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&auth_type=rerequest
scope=email
使用此参数时,登录对话框会重新请求已拒绝的权限。
在流程的这一阶段,用户已完成身份验证并登录。应用也已准备好代表用户发出 API 调用。执行此操作前,应用应存储访问口令和应用用户的登录状态。
从前述步骤中收到访问口令后,应用应将其妥善存储,以便应用的所有部分在应用发出 API 调用时使用。此部分并无明确的流程,但通常来说,如果您构建的是网页应用,则建议您添加口令作为会话变量,以便识别特定用户与该浏览器进行的会话;如果您构建的是原生桌面或移动应用,则应使用应用适用的数据存储。此外,应用应将口令与 user_id
一起存储到数据库,以供识别。
请参阅我们关于访问口令文档中的访问口令大小的说明。
同样,您的应用应存储用户的登录状态,这有助于避免再次调用登录对话框。无论您选择的是哪种流程,请调整您的登录状态检查,纳入此项功能。
您可以通过撤销所添加的任何登录状态标签,让用户退出应用,例如删除指示用户已登录的会话。您还需要移除已存储的访问口令。
让用户退出并不等同于撤销登录权限(移除之前认可的验证),撤销登录权限可单独执行。因此,构建应用时,要保证其不会自动强制已退出的用户返回登录对话框。
用户可以通过 Facebook.com 卸载应用,而无需与应用进行交互。为帮助应用检测这类事件,我们允许应用提供取消授权回调网址。在发生该事件时,系统会向该网址发送通知。
您可以通过应用面板启用取消授权回调。
用户可以请求应用删除从 Facebook 接收的所有用户相关信息。如需响应这些请求,请参阅数据删除请求回调。