现在前后端分离比较流行,如果项目集成第三方登录,一般集成也是由前端完成.

前端把 user_id 与 token 相关信息传给后端,后端需要验证 user_id 与 token 的有效性,否则伪造新用户的成本非常低.

本文主要讲 google 与 facebook 的登录的 token 验证. 如果需要看国内第三方登录的,可以直接略过此文.

Google 篇

前端集成可以看此文档 https://developers.google.com/identity/sign-in/web/sign-in .

本文已经相关的 html 复制保存到 gist https://gist.github.com/mangege/ff9a41ff2898cf19f88070e2945519c7#file-g-html ,把页面上的 google-signin-client_id 值改成你的即可.

之后用 python2 -m SimpleHTTPServer 运行一个 web server , 访问 http://localhost:8000/g.html .

登录后可以在浏览器的控制台看到 id_token 的值, 复制出来备用.

后端验证 Google 的文档,找的好辛苦. https://developers.google.com/identity/sign-in/web/backend-auth

验证很简单, 替换此连接的 XYZ123 为之前复制的 id_token https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123 ,直接到浏览器访问即可. 或使用 curl 命令.

Example

我们主要要验证结果的 aud 与 sub , aud 保证此 token 为你的站点生成, sub 保证 user_id 的正确性.

Facebook 篇

前端集成可以看此文档 https://developers.facebook.com/docs/facebook-login/web .

gist https://gist.github.com/mangege/ff9a41ff2898cf19f88070e2945519c7#file-fb-html

后端验证 Facebook 的文档没找到直接的,是翻到 debug_token 这个接口觉得符合需求,就用它了.

Facebook PHP SDK 有提到与 JS 结合 https://developers.facebook.com/docs/php/howto/example_access_token_from_javascript .

看了一下 PHP SDK 的实现, 主要通过读取 cookies 里面 fbsr_ 的值来进行验证 https://github.com/facebook/facebook-php-sdk-v4/blob/master/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php#L158 . 太复杂,想找简单的接口实现.

最初的想法是直接拿到前端的 access token, 再后端去调用 /me 接口,成功则有效. 后来仔细考虑过.这也会导致有安全漏洞.比如某站长拿自己网站的用户 access_token 来登录,这样是有效的,因为 /me 接口无法验证 access_token 的来源.

后来在这里看到 debug_token https://developers.facebook.com/docs/facebook-login/access-tokens/debugging-and-error-handling ,觉得返回很适合用来做验证.

对应的 graph api 文档 https://developers.facebook.com/docs/graph-api/reference/v2.6/debug_token

因为我们把 用户的 access_token 作为 input_token 传给了 /debug_token 接口,所以调用 /debug_token 接口我们得传应用的 access_token .
应用的 access_token 有两种方式生成,一种是通过接口生成,另外一种是把 app_id 与 app_secret 拼接在一起作为 access_token 传给接口.
拼接的这种方式简单,我们就是拼接. https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens

最终我们只要把页面拿到的 access_token 和拼接出来的 access_token 传给 /debug_token 接口即可.

[Example](https://graph.facebook.com/v2.6/debug_token?input_token=EAAVUeqi4jXwBAFgQrjEc1rfHe2pwqaNmCjJd2gLFOsati3IgVeiFFt1udjU9JrkP04hot0YbMm6VZCHLXdA90LBTrlIyniNXsXIW46EuEFfEFXVFOoBZCSIFNHp3SQF22CJHbiW6bjbCzUuoPhFeNhBnDU6L8cG60wKZAWByQZDZD&access_token=1500260676963708 018f0e4ee844e4a06f2854dc31242a10)

最终 Ruby 代码

gist : https://gist.github.com/mangege/ff9a41ff2898cf19f88070e2945519c7#file-auth_token_util-rb

这样就不用安装 google 或 facebook 的 sdk.