coderLMN / AutomatedDataCollectionWithR

《基于 R 语言的自动化数据采集技术》读者讨论区
28 stars 10 forks source link

关于OAuth身份验证的一些问题 #4

Open jlhnihao opened 8 years ago

jlhnihao commented 8 years ago

吴老师好,对于从API检索数据与 OAuth 身份验证的这两节,有一些不清楚的地方,还请您指导: 因为某些原因,不能访问 facebook 这样的网站,但9.1.10节的雅虎天气案例目前似乎需要进行这样的身份验证,然后才可继续对前面 API 的具体运用,若以注册雅虎天气订阅源为例:

(1).咱们怎么发现 OAuth 的授权和访问(令牌)端点呢? (2).在执行 token 之前,怎么理解书本里说描述的准备工作(P220),“在浏览器里向应用加入一个URL,通过在 Settings 部分加入一个网站并指定一个站点URL来进行。" 前面这个 Settings 部分加入一个网站是怎么加呢?怎么理解这个?。本地主机:"http://localhost:1410/ "与使用 oauth_callback() 来获取的监听器的回调 URL 是有什么关系呢?二者都适用于前面所说的指定的一个站点 URL 么? (3).定义申请的许可范围时,通常怎样找到所需的许可清单的信息呢?

问题可能有些小白,烦请吴老师不吝指教。如果您觉得要解释里面的知识时,若涉及到一些太浅易或者常识性问题的时候,可略而不谈而只给出一些参考方向。

coderLMN commented 8 years ago

(1) OAuth 的授权和访问端点一般都会在网站的 developers 页面(即开发者网页)里说明,或者通过搜索 " 网站名 + OAuth " 关键字找到。比如针对 Yahoo 的 OAuth 验证,在无法使用 Google 的时候,用 bing.com 搜索 "yahoo OAuth" (珍爱生命,远离百度)找到的第一个结果就是 Yahoo 的开发者网络里关于 OAuth 的内容: https://developer.yahoo.com/oauth/ ,在 Documentation 里就可以找到具体的授权方法。

(2) P220 页这部分内容是专门针对 Facebook 的 OAuth 验证细节。这里的 Settings 部分是指,用户在 Facebook 的网页上注册成为开发者并加入了自己的一个应用之后,在该应用的管理页面上右侧菜单有一个 Settings 可以设置该应用的一些基本选项,其中有一项是该应用对应的网站 Website ,可以添加一些网站的 URL 进去,没有登记在这个网站列表里的 URL 就无法得到 Facebook 返回的信息。这个 URL 可以填写本地主机 "http://localhost:1410/ " 也可以在 R 里调用 oauth_callback() 获取回调 URL(一般就是 http://localhost:1410/ ,不过我还没仔细研究过为什么是这个 URL,直观印象上应该是 R 的 httr 组件指定的接收返回信息的链接) 再填写回去。具体情况如下图所示: fb1

设置 URL 的情况如下图所示: fb2

经过尝试可以发现,本书中关于 Facebook 的 OAuth 授权的内容已经有不少变化。例如,Facebook 的许可清单里有些内容(例如示例代码里的 user_checkins 等等)被取消了或名称已经改变,新版本 httr 组件的某些函数也修改了格式,所以原书的代码会产生一些错误,如下图所示: fb4

这也是我在另一个 issue 里给读者的一个提醒:这本书是关于网络抓取的,而网站的改版不会通知读者而且是经常会发生的,因此请读者不要照搬书中的代码,而是通过书中的示例掌握原理和方法,然后自己去阅读网站上的文档,才能做出有用的东西。

(3) 许可范围的清单是随着网站的不同而不同的,而且不一定每个网站都有这么一项设置。如果需要,在开发者网站上的 OAuth 文档里应该都能够找到相关清单。

coderLMN commented 7 years ago
  1. 你可以再看一下 p. 219,authorize 对应的是获取临时证书的网址,而 access 对应的是获得访问令牌证书的网址。这是根据 OAuth 的原理来实现的,具体的两个网址需要查看要访问的网站的文档。

  2. 这个错误信息就是说你的系统参数 FACEBOOK_CONSUMER_SECRET里没有 secret 。从你前面给出的代码Sys.setenv(FACEBOOK_CONSUMER_SECRET="应用秘钥") 来看,估计你给的是 app ID 而不是 secret,所以这个系统参数出错了。

你在fb_app<-oauth_app("facebook","817513598388292") 里提供的应用 ID 是密钥,和这个 secret 配套才能用来申请访问证书,而这个 secret 是保密的,不应该和应用 ID 一起出现在代码里,否则别人看到你的代码就获取了你的访问信息了。这就是为什么要把它通过 Sys.setenv(FACEBOOK_CONSUMER_SECRET="secret")放到系统参数里而不是代码里的原因。

这两个问题的答案其实都在 p. 219 解释了,你可能没有完全理解它,这部分确实有点难度,需要多花点时间。

dayushan commented 7 years ago

吴老师 我今天又仔细看了下书,查了点资料 运行如下代码:

facebook<-oauth_endpoint(authorize="https://www.facebook.com/dialog/oauth",access="https://graph.facebook.com/oauth/access_token")
Sys.setenv(FACEBOOK_CONSUMER_SECRET="消费者秘密")
fb_app<-oauth_app("facebook","817513598388292")
permissions<-"user_birthday,user_education_history,user_hometown,user_location,user_website,user_work_history,publish_actions,user_friends,email"
fb_token<-oauth2.0_token(facebook,fb_app,scope=permissions,type='application/x-www-form-urlencoded')###scope就是请求的权限

R Console 会提示输入你的选择(1:Yes, 2:No) ,键盘输入“1” 提示:

Adding .httr-oauth to .gitignore
httpuv not installed, defaulting to out-of-band authentication(默认为带外认证)
Please point your browser to the following url:
https://www.facebook.com/dialog/oauth?client_id=此处为消费者密钥&scope=user_birthday%2Cuser_education_history%2Cuser_hometown%2Cuser_location%2Cuser_website%2Cuser_work_history%2Cpublish_actions%2Cuser_friends%2Cemail&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code

然后我通过浏览器输入上述网址时提示了一句话,翻译后是“重定向网址不被支持”

当我再运行上述代码时报错:

###Error in curl::curl_fetch_memory(url, handle = handle) :

Timeout was reached

请问这怎么解决呢?

coderLMN commented 7 years ago

“重定向网址不被支持” 的错误信息原文是什么?可以到 stackoverflow 里去查一下。

dayushan commented 7 years ago

运行完代码就有提示 R Console 会提示输入你的选择(1:Yes, 2:No) ,键盘输入“1” 提示:

Adding .httr-oauth to .gitignore
httpuv not installed, defaulting to out-of-band authentication(默认为带外认证)
Please point your browser to the following url:
https://www.facebook.com/dialog/oauth?client_id=此处为消费者密钥&scope=user_birthday%2Cuser_education_history%2Cuser_hometown%2Cuser_location%2Cuser_website%2Cuser_work_history%2Cpublish_actions%2Cuser_friends%2Cemail&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code
然后我通过浏览器输入上述网址后提示“The redirect_uri URL is not supported”
zai再过一段时间会提示:
###Error in curl::curl_fetch_memory(url, handle = handle) :
Timeout was reached

我去网上搜了一下,提示“The redirect_uri URL is not supported”可能是因为“The provided redirect_URI is not supported for this request type.”,但是不知道怎么解决。

coderLMN commented 7 years ago

错误信息里提到的redirect_uri 实际上就是前面网址最后那一段里的 redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob ,这个 uri 转码过来就是 urn:ietf:wg:oauth:2.0:oob 。出错的原因是 Facebook 的接口并不支持这个 OAuth 缺省产生的 uri ,所以还要去读 Facebook 有关 OAuth 的文档。

另外,我在前面提到了,Facebook 的许可清单里有内容(例如示例代码里的 user_checkins 等等)被取消或名称已改变,照搬原书代码会出错,你可以一个一个加(比如先加 user_birthday 不加其他的试试),但是最重要的还是去看要访问的网站的技术文档,了解它的 API 具体格式和要求。

dayushan commented 7 years ago

1、那个许可清单我是根据权限里边的参考文档复制过来的,并不是照搬书上的,即使只留下user_birthday,还是同样的问题。 2、我使用httr包中关于facebook的demo(代码附在此段后)也是要通过浏览器输入https://www.facebook.com/dialog/oauth?client_id=353609681364760&scope=&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code 输入后仍然提示“The redirect_uri URL is not supported”。 Facebook的demo代码:

library(httr)
# 1. Find OAuth settings for facebook:
#    http://developers.facebook.com/docs/authentication/server-side/
oauth_endpoints("facebook")

# 2. Register an application at https://developers.facebook.com/apps/
#    Insert your values below - if secret is omitted, it will look it up in
#    the FACEBOOK_CONSUMER_SECRET environmental variable.
myapp <- oauth_app("facebook", "353609681364760", "1777c63343eba28359537764fab99b9a")

# 3. Get OAuth credentials
facebook_token <- oauth2.0_token(
  oauth_endpoints("facebook"),
  myapp,
  type = "application/x-www-form-urlencoded"
)

# 4. Use API
req <- GET("https://graph.facebook.com/me", config(token = facebook_token))
stop_for_status(req)
str(content(req))

3、我今天看了一天的文档,关于API ,关于OAuth,且网上有一段是这样说的:

By default, all apps are created with a redirect_uri set to urn:ietf:wg:oauth:2.0:oob. Rather than redirecting authorization requests to another service, this URI tells us that you would like the access_code and access_token provided in a standard HTML response. The code or token will be returned in the title element on its own in the response, so if you would like to use this redirect_uri, you may simply retrieve the title element’s inner contents.

然而我还是不知道该怎么解决这个问题,还请吴老师赐药,拜托了

coderLMN commented 7 years ago

前面的错误信息里面,我们都遗漏了一句话:

httpuv not installed, defaulting to out-of-band authentication

这是一条重要信息。在安装了 httpuv 包之后,缺省浏览器自动打开并完成了身份验证。

install.packages("httpuv")
library(httpuv)
facebook_token <- oauth2.0_token(
   oauth_endpoints("facebook"),
   myapp,
   type = "application/x-www-form-urlencoded"
)

看似正常了,但是 Authentication complete. 这句话后面还跟了一条错误信息,会影响到后续操作:

Waiting for authentication in browser... Press Esc/Ctrl + C to abort Authentication complete. Error in init_oauth2.0(self$endpoint, self$app, scope = self$params$scope, : Bad Request (HTTP 400).

继续查找这条错误信息,发现 httr 包的服务器端口有个系统参数需要提前设置好:

Sys.setenv("HTTR_SERVER_PORT" = "1410/")

设置好它之后,就能够顺利完成身份验证的过程了。

dayushan commented 7 years ago

@coderLMN 老师你的没有报错吗?

library(httpuv)
#install.packages("http://cran.r-project.org/src/contrib/Archive/httr/httr_0.6.1.tar.gz",repo=NULL, type="source")
#install.packages("Rfacebook")
library(rjson)
library(Rfacebook)

library(httr)
Sys.setenv("HTTR_SERVER_PORT" = "1410/")

# 1. Find OAuth settings for facebook:
#    http://developers.facebook.com/docs/authentication/server-side/
oauth_endpoints("facebook")
# 2. Register an application at https://developers.facebook.com/apps/
#    Insert your values below - if secret is omitted, it will look it up in
#    the FACEBOOK_CONSUMER_SECRET environmental variable.
myapp <- oauth_app("facebook", "AppID", "Appsecret")
permissions<-"user_birthday,user_education_history,user_hometown,user_location,user_website,user_work_history,publish_actions,user_friends,email"
Sys.setenv("HTTR_SERVER_PORT" = "1410/")
# 3. Get OAuth credentials
facebook_token <- oauth2.0_token(
  oauth_endpoints("facebook"),
  myapp,
  scope=permissions,
  type = "application/x-www-form-urlencoded"
)

**Waiting for authentication in browser...
Press Esc/Ctrl + C to abort
Authentication complete.
Error in curl::curl_fetch_memory(url, handle = handle) : 
  Timeout was reached**
**得到的网址是#####http://localhost:1410/?code=某个字符串**

fb_sig<-sign_oauth2.0(fb_token)
**Deprecated: supply token object to config directly**
coderLMN commented 7 years ago

我这里是正常的。你是不是没有在 Facebook app 里设置网站的 url ?看这个 Timeout 的报错怀疑和它有关。

你可以看一下我这个评论 里的步骤和那两个截图。

coderLMN commented 7 years ago

另外,后面那条提示:

fb_sig<-sign_oauth2.0(fb_token) Deprecated: supply token object to config directly

是说 sign_oauth2.0() 这个函数已经废弃了,可以直接把 token 对象赋值给 config 。

dayushan commented 7 years ago

image 嗯 我看了老师关于设置那部分的评论

coderLMN commented 7 years ago

那应该是你用来翻墙的 proxy 造成的问题。在调用 httr 包里的函数之前,需要先设置好 proxy 参数:

library(httr)
set_config(use_proxy(url = "*****_", port = "_"))

这样应该就可以了。

dayushan commented 7 years ago

我用的是蓝灯
image

image

coderLMN commented 7 years ago

端口号外面不要带引号,不然成字符串而不是数值了。

set_config(use_proxy(url = "127.0.0.1", port = 55720))
dayushan commented 7 years ago
Sys.setenv("HTTR_SERVER_PORT"= "1410/")
set_config(use_proxy(url = "127.0.0.1", port = 55720))

# 3. Get OAuth credentials
facebook_token <- oauth2.0_token(
  oauth_endpoints("facebook"),
  myapp,
  scope=permissions,
  type = "application/x-www-form-urlencoded"
)

image

coderLMN commented 7 years ago

你用的 httr 是 1.2.0 版本吧?我的 1.1.0 没有这个问题。

在网上看了一下,似乎这个报错的原因是 1.2.0 版在这方面不稳定,建议是回退到 1.1.0 版:

library(devtools)
install_version("httr", version = "1.1.0", repos = "http://cran.us.r-project.org")
library(httr)

你可以试试看。

dayushan commented 7 years ago

还是同样的问题 获取access token 失败 试了几个版本的httr都不行 唉,怎么办?

coderLMN commented 7 years ago

别着急,调代码是需要耐心的。错误信息非常重要,要仔细分析,一般常见的问题都可以在Google上搜报错信息找到解决办法。实在找不到的,还可以去看出错包里相关的源代码。总之,调代码有时候是需要很多时间到。

dayushan commented 7 years ago

应该是这个包的问题 我试了httr包里所有的demo,都会报错

dayushan commented 7 years ago

@coderLMN 老师,我了一个文档说客户端认证流程:客户端和服务器端认证流程在请求认证窗口唯一不同的地方时,在参数中加入response_type,值为token

https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&response_type=token

而我们在提交参数发出请求进行认证时响应是以code返回,即 http://localhost:1410/?code=AQBF2SpAt8Z7aRnP6R5Gm0QU8CLX3mqdHBUek01dwtCbjI-lzLv1mdP2OuuMmRUnbsKkqxVla1JzQ0Sclxk777SFFcjiVmvbZFKoSgSWgabpuctcgpen4VCwS0JsmGlibpXjD6b-7qYqqV6yPLN-aLMj04I1-QYwBE5iS1cqwDHWSVCijMMv9_FSip_p3bc0l6iLc38DqDkwKLhFhmBsRVm17ZH-WCJgJIIoiypwwoNZj8zjp-fXwfRotze_LtWffdjPAYQoLKu7p1sbXrC5IwHX0WaYGXQx02jR3c6RGvhZpgT8fITOweEw68_lEGp7So1W0umTdo-lL9pQJunyc22j&state=pGMtSmtxbn#_=_

程序报错会受这个影响吗

coderLMN commented 7 years ago

这两个 URL 的作用是不同的,一个是提交验证,另一个是在通过验证后获取验证码。

我怀疑这个问题还是和你用的 proxy 有关系,因为我直接用 hosts 访问 FB 没有遇到这个问题。你可以试试用这个办法:https://laod.cn/hosts/2016-google-hosts.html ,然后去掉 proxy 以及 set_config(use_proxy(url = "*****_", port = "_")) 这行代码,再重新试试。

dayushan commented 7 years ago

木有效果 还是取不到access token 呜呜

coderLMN commented 7 years ago

我对于 FB 接口测试运行的完整代码及各步骤输出如下:

> library(httr)
> library(httpuv)
> Sys.setenv("HTTR_SERVER_PORT" = "1410/")
> facebook<-oauth_endpoint(authorize="https://www.facebook.com/dialog/oauth",
    access="https://graph.facebook.com/oauth/access_token")
> Sys.setenv(FACEBOOK_CONSUMER_SECRET="262c***********************e8")
> fb_app<-oauth_app("facebook","10***************15")
> permissions<-"user_birthday,user_education_history,user_hometown,user_location,
    user_website,user_work_history,publish_actions,user_friends,email"
> fb_token<-oauth2.0_token(facebook,fb_app,scope=permissions,
    type='application/x-www-form-urlencoded')  #需要在浏览器打开的 FB 授权页面上确认

Waiting for authentication in browser... Press Esc/Ctrl + C to abort Authentication complete.

fb_token  #显示获取的 token
<Token>
<oauth_endpoint>
 authorize: https://www.facebook.com/dialog/oauth
 access:    https://graph.facebook.com/oauth/access_token
<oauth_app> facebook
 key:    10***************15
 secret: <hidden>
<credentials> access_token, expires
> library(Rfacebook)
> getUsers("hadleywickham", fb_token, private_info = FALSE)  
#现在 FB 的接口已经改了很多,不允许通过用户名访问其他用户的信息,
#而且必须对方事先允许你的 app 去访问才能通过接口获取信息,因此原书代码会有如下错误:

Error in callAPI(query, token) : (#803) Cannot query users by their username (hadleywickham)

> req <- GET("https://graph.facebook.com/me", config(token = fb_token)) #改用自己的信息
> stop_for_status(req)
> str(content(req))

List of 2 $ name: chr "J****" $ id : chr "11****82"

我的完整环境信息如下,可以仔细核对一下有什么不同:

> sessionInfo()

R version 3.1.3 (2015-03-09) Platform: x86_64-apple-darwin13.4.0 (64-bit) Running under: OS X 10.12.1 (unknown)

locale: [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages: [1] stats graphics grDevices utils datasets methods base

other attached packages: [1] Rfacebook_0.6.3 rjson_0.2.15 httpuv_1.3.3 httr_1.1.0

loaded via a namespace (and not attached): [1] curl_0.9.6 jsonlite_0.9.19 openssl_0.9.2 R6_2.1.2 Rcpp_0.12.3 tools_3.1.3

R 语言有个很大的问题,就是不同版本的包之间有时候兼容性不好,这需要很大的耐心去调试。

dayushan commented 7 years ago

image

老师,这是我的环境信息 还是不能运行 image 我还是用昨晚的那个笨办法吧 ,修改后能提取部分个人信息 如果我不能提取其他用户的信息,那Facebook有没有公众流呢 毕竟我刚用脸书,能获取的资源很有限 或者说Facebook API还能获取什么资料?还有其他用途吗?

coderLMN commented 7 years ago

你的 httr 还是 1.2.1 版本,浏览器打开之前还要选择 1: Yes 2: No,这都和我的情况不一样。先把版本都弄成兼容的,再走下一步吧。

Facebook API 有很详细的接口文档,我还没有认真读过,你可以先看一看有哪些你感兴趣的内容:https://developers.facebook.com/docs/apis-and-sdks

dayushan commented 7 years ago

image image b把电脑除1.1.0版本的httr都删了,然后获取不到sessionInfo(), 打开浏览器选1选2的我这边有,Rfacebook也是0.6.3版本,就是httr做不到版本统一

coderLMN commented 7 years ago

把 httr 全部删了,然后执行这个安装命令:

library(devtools)
install_version("httr", version = "1.1.0", repos = "http://cran.us.r-project.org")
library(httr)
sessionInfo()
dayushan commented 7 years ago

image

coderLMN commented 7 years ago

为什么有错误信息说 httpuv 包不存在?另外,你访问 FB 用了 proxy 吗?

dayushan commented 7 years ago

刚开始没有指定库的位置,所以没取上httpuv,取到后是v1.3.3 image

coderLMN commented 7 years ago

我的另外一台 Mac 上也遇到了这个问题,似乎是 R 的版本高了。你用 v 3.1.3 的 R 试试,确保所有包的版本也和我前面的一致,这样把版本兼容问题先孤立出来,调试会简单一些。

dayushan commented 7 years ago

image 老问题

coderLMN commented 7 years ago

你这还是 3.2 版的 R,建议用 3.1 版,然后重新安装最前面警告信息里的两个包。

dayushan commented 7 years ago

image

coderLMN commented 7 years ago

这个问题在网上似乎搜不到靠谱的答案,只找到这一个问题 http://stackoverflow.com/questions/37932662/getting-error-in-readrdscache-path-error-reading-from-connection ,还没什么人回答,只有 httr 的作者 hadley 大神回了一句:建议安装 httr 开发版,不明白是怎么回事。

有空了我会去看看 httr 的源代码。你现在有时间可以去看一下,报这个错误信息是在什么地方,符合了什么样的条件,然后倒回去看自己的环境是哪里出问题了。

dayushan commented 7 years ago

前两天我在stack flow上也搜到类似问题 大神把讨论区关了 还是很感谢老师,这么耐心地帮我解决问题 谢谢了