【问题标题】:Error when accessing Rdio oauth API with dispatch in scala在 scala 中使用调度访问 Rdio oauth API 时出错
【发布时间】:2014-05-05 15:31:24
【问题描述】:

我正在尝试使用 scala dispatch 来访问 Rdio API,如下所示:

import dispatch.url
import dispatch.Http
import dispatch.Defaults.executor
import dispatch._
import com.ning.http.client.oauth.ConsumerKey
import dispatch.oauth._

val consumer = new ConsumerKey("my key", "my secret")
val params = Map("method" -> "get", "keys" -> id, "extras" -> "-*,playCount")
val request = url("http://api.rdio.com/1/").POST <@ consumer << params <:< Map("Accept" -> "application/json")
val response = Http(request OK as.String)

我收到错误 403。

怎么了?我确定我的密钥是正确的。

【问题讨论】:

  • 不熟悉 Scala,但我在 Rdio 工作。您是在 POST 请求的正文中还是在查询字符串中传递这些参数?请求的正文是正确的做法。此外,建议使用通过 Authorization 标头传递 OAuth 凭据。
  • 是的, 来传递身份验证标头
  • 您使用的是哪个版本的调度?
  • 我使用 dispatch 0.11 版本

标签: web-services scala oauth scala-dispatch rdio


【解决方案1】:

我已经分析了 rdio 页面上的 python 示例和 Scala 的区别。

我认为确实存在两个问题。

  1. 首先是需要获取访问令牌。

  2. 第二个问题,很明显dispatch库的sign方法让rdio不爽。它删除了尾部斜杠,这使得签名不匹配。

第一个问题很容易解决 - 您只需使用 Exchange 类,它会为您完成大部分工作。

第二个问题非常棘手,我只是复制了原始的sign 方法并更改了删除尾部斜杠的部分。

代码如下。

val ck = new ConsumerKey("YOUR_CONSUMER_KEY", "YOUR_CONSUMER_TOKEN")

// declare exchange to obtain an access token
val exchange = new Exchange with SomeHttp with SomeCallback with SomeConsumer with SomeEndpoints {

  override def http: HttpExecutor = Http

  override def callback: String = "oob"

  override def consumer: ConsumerKey = ck

  override def accessToken: String = "http://api.rdio.com/oauth/access_token"

  override def authorize: String = "http://api.rdio.com/oauth/authorize"

  override def requestToken: String = "http://api.rdio.com/oauth/request_token"
}

/// we change the default method of the dispatch
def sign(request: Req, consumer: ConsumerKey, token: RequestToken): Req = {
  val calc = new OAuthSignatureCalculator(consumer, token)
  request underlying { r =>
    val req = r.build
    //!!! here we make change so the trailing slash is not removed
    val baseurl = req.getURI.toString.takeWhile(_ != '?').mkString("")
    calc.calculateAndAddSignature(baseurl, req, r)
    r
  }
}

val response = exchange.fetchRequestToken.right.flatMap { rt =>

  // point your browser to this URL with the given oauth token, we'll get PIN back
  println(s"Go to https://www.rdio.com/oauth/authorize/?oauth_callback=oob&oauth_token=${rt.getKey}")
  print("Enter PIN:")
  val pin = readLine()

  exchange.fetchAccessToken(rt, pin)
}.right.flatMap { at =>
  // now we can call API using the consumer key and the access token
  val request = sign(url("http://api.rdio.com/1/").POST << Map("method" -> "currentUser"), ck, at)
  val response = Http(request > as.String)
  response.map(Right(_))
}

response.map { responseOrError =>
  responseOrError.fold(err => println(s"Error $err"), suc => println(s"Response: $suc"))
  Http.shutdown()
}

【讨论】:

  • 我没有使用用户特定的数据,只打开曲目中的元数据。我想我不需要获得令牌。我通过使用 Rdio Simple Java Version (github.com/rdio/rdio-simple/tree/master/java) 找到了解决方案,放弃了调度。
猜你喜欢
  • 2016-02-10
  • 2015-11-04
  • 2015-06-07
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多