前言

继关于服务端如何接入Apple, Google 的第三方登录之后,这里介绍在整合FacebookInstagram 的第三方登录时服务端的验证工作。

Facebook

Facebook的登录验证与Google相似,同样是验证客户端通过登录请求获取到的登录token是否有效。

根据官方文档 显示,Facebook的身份验证有两种方式:

  1. 通过code交换access_token,然后用获取的access_token访问API验证客户端传来的登录token是否有效。服务端收到客户端传来的code后,通过Facebook的API( https://graph.facebook.com/v9.0/oauth/access_token )交换访问口令,即access_token。最后调用API( https://graph.facebook.com/debug_token?input_token={token-to-inspect}&access_token={app-token-or-admin-token} )验证登录token是否有效。

         var (
             clientId     = "your clientId"
             clientSecret = "your clientSecret"
             code         = "your code"
             redirectUri  = "your redirectUri"
             url          = fmt.Sprintf("https://graph.facebook.com/v9.0/oauth/access_token?client_id=%s&redirect_uri=%s&client_secret=%s&code=%s", clientId, redirectUri, clientSecret, code)
         )
            
             response, err := http.Get(url)
             handleResponse(response)
             handleErr(err)
    

    API返回的结果:

     {
       "access_token": {访问口令}, 
       "token_type": {type},
       "expires_in":  {还有多久过期, 单位: }
     }
    
         var (
             accessToken = "get from above"
             token = "your token"
         )
            
             response, err := http.Get(fmt.Sprintf("https://graph.facebook.com/debug_token?input_token=%s&access_token=%s", token, accessToken))
             handleResponse(response)
             handleErr(err)
    
  2. token API

    客户端授权并取得Facebook返回的登录token后,将token传给服务端,服务端通过API( https://graph.facebook.com/debug_token?input_token={token-to-inspect}&access_token={app-token-or-admin-token} )

    其中input_token为客户端传过来的登录token,access_token为API访问口令,注意这里的access_token不是通过API获取的,而是client_id|client_secret

     var (
             clientId     = "your clientId"
             clientSecret = "your clientSecret"
             token        = "your token"
             url          = fmt.Sprintf("https://graph.facebook.com/debug_token?input_token=%s&access_token=%s|%s", token, clientId, clientSecret)
     )
        
         response, err := http.Get(url)
         handleResponse(response)
         handleErr(err)
    

    具体是code还是token API,取决于客户端在用户点击登录按钮时,客户端发起请求中response_type的值。根据官网显示,response_type的值包括:

    解释
    code 响应数据作为网址参数纳入,且包含 code 参数(每个登录请求独有的加密字符串)。如果未指定此参数,这便是默认行为。当服务器处理口令时,这尤其有用
    token 响应数据作为网址片段纳入,且包含访问口令。桌面应用必须为 response_type 选用此设置。当客户端处理口令时,这尤其有用
    code%20token 响应数据作为网址片段纳入,且包含访问口令和 code 参数
    granted_scopes 返回用户在登录时授予应用的所有权限的逗号分隔列表。可与其他 response_type 值合并。与 token 合并时,响应数据作为网址片段纳入;与其他值合并时,响应数据则作为网址参数纳入。

token验证API返回的结构为:

{
    "data": {
        "app_id": 138483919580948,  //应用ID,等于client_id
        "type": "USER", 
        "application": "Social Cafe", 
        "expires_at": 1352419328, //token过期时间
        "is_valid": true,  //是否有效
        "issued_at": 1347235328, //什么时候签发的
        "metadata": {
            "sso": "iphone-safari"
        }, 
        "scopes": [ //权限范围
            "email", 
            "publish_actions"
        ], 
        "user_id": "1207059" //用户在该应用下的唯一ID,类似于微信的OpenID
    }
}

最后如果需要服务器自己获取用户的头像、昵称、性别等信息,需要服务端通过前面获取到的access_token自己去调用Facebook对应的API:

API: https://graph.facebook.com/{facebook_user_id}?fields=name,picture&access_token={access_token}

其中fields字段根据自己的需求填写,用,分隔,具体参考官方文档

Instagram

根据Instagram官方文档 显示,Instagram不推荐使用Instagram作为身份验证解决方案,其推荐使用Facebook登录, 但是为了调用Instagram的图谱API,需要开发者完成如下准备工作:

  1. Instagram Business 帐户Instagram 创作者帐户
  2. 与该帐户相关联的 Facebook 公共主页
  3. 一个 Facebook 开发者帐户,可在公共主页上执行任务
  4. 已注册的 Facebook 应用 ,且已配置基本设置

这里介绍如果通过Instagram 图谱 API 获取Instagram的访问口令以及用户信息

客户端在App内集成Instagram授权窗口后,在用户授权后客户端将获取授权码,并将其传给服务端,然后客户端使用该授权码来换取访问口令(access_token)。

这里需要注意的是,Instagram返回的授权码包含了后缀#_,所以使用时需要将#_去掉才是真正的授权码

交换访问口令的API: https://api.instagram.com/oauth/access_token, 需要的参数有:

参数名 参数值
client_id Instagram应用ID
client_secret 应用密钥
redirect_uri Instagram后台配置的用户授权后的重定向URI
grant_type 固定值: authorization_code
code 授权码(注意去掉#_后缀)
    tokenParam := fmt.Sprintf("client_id=%s&client_secret=%s&grant_type=authorization_code&redirect_uri=%s&code=%s", clientId, clientSecret, redirectUri, code)
	response, err := http.Post(tokenUrl, "application/x-www-form-urlencoded", strings.NewReader(tokenParam))
	if err != nil {
		log4go.Errorf("%v\n", err)
		panic(err)
	}
    if response.StatusCode != http.StatusOK {
    	panic(err)
    }

返回的结果格式为:

{ 
  "access_token": "IGQVJ...", //访问口令 
  "user_id": 17841405793187218  //Instagram 应用中用户的唯一ID,类似于微信的OpenID
}

最后使用API: https://graph.instagram.com/{instagram_user_id}?fields=username&access_token={access_token} 查询用户节点,其中fields字段参考用户节点文档

参考资料

Facebook登录

手动构建登录流程

Facebook User

Instagram官方文档

Instagram 图谱 API

Instagram 用户节点文档