我在Scala上尝试了mklink .htaccess C:\path\outside\.htaccess
mklink /D .upload C:\path\outside\upload
,但收到了错误GET https://api.twitter.com/1.1/statuses/user_timeline.json?count=1&user_id=XXX
。
这是我的规格:
401 Authorization required
:
build.sbt
name := "hoge"
version := "1.0"
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-ws" % "2.4.0-M2",
"commons-codec" % "commons-codec" % "1.3.0"
)
:
hoge.scala
在这种情况下, import scala.concurrent.ExecutionContext.Implicits.global
import java.net.URLEncoder
import javax.crypto.spec.SecretKeySpec
import javax.crypto.Mac
import play.api.libs.json._
import play.api.libs.ws.ning.NingWSClient
import org.apache.commons.codec.binary.Base64
object Hoge {
def main(args: Array[String]) = {
val consumerKey = "AAA"
val consumerSecret = "BBB"
val token = "CCC"
val tokenSecret = "DDD"
val timestamp = (System.currentTimeMillis / 1000).toString
val nonce = System.nanoTime.toString
val id = "XXX"
val host = "https://api.twitter.com"
val path = "/1.1/statuses/user_timeline.json"
val url = host + path
val query = Map(
"count" -> "1",
"user_id" -> id
)
val sign = signature(
url, consumerKey, consumerSecret, token, tokenSecret, timestamp, nonce, query
)
val header = Map(
"Content-Type" -> "application/x-www-form-urlencoded;charset=UTF-8",
"Authorization" -> oauthHeader(consumerKey, token, sign, timestamp, nonce)
)
val ws = NingWSClient()
val res = get(ws)(url, query, header)
Thread.sleep(3000)
res.value.get.get.json
ws.close()
}
def signature(url: String, consumerKey: String, consumerSecret: String, token: String, tokenSecret: String, timestamp: String, nonce: String, query: Map[String, String]) = {
val params = Map(
"oauth_consumer_key" -> consumerKey,
"oauth_nonce" -> nonce,
"oauth_signature_method" -> "HMAC-SHA1",
"oauth_timestamp" -> timestamp,
"oauth_token" -> token,
"oauth_version" -> "1.0"
) ++ query
val paramsEncoded = params.toList.sorted map { case (k, v) => urlencode(k) + "=" + urlencode(v) }
val paramString = paramsEncoded mkString "&"
val signatureBase = "GET&" + urlencode(url) + "&" + urlencode(paramString)
val signingKey = urlencode(consumerSecret) + "&" + urlencode(tokenSecret)
base64encode(encry(signingKey, signatureBase))
}
def oauthHeader(consumerKey: String, token: String, sign: String, timestamp: String, nonce: String) = {
val params = Map(
"oauth_consumer_key" -> consumerKey,
"oauth_nonce" -> nonce,
"oauth_signature" -> sign,
"oauth_signature_method" -> "HMAC-SHA1",
"oauth_timestamp" -> timestamp,
"oauth_token" -> token,
"oauth_version" -> "1.0"
).toList.sorted
"OAuth " + (params map { case (k, v) => urlencode(k) + "=\"" + urlencode(v) + "\"" } mkString ", ")
}
def urlencode(s: String) = {
URLEncoder.encode(s, "UTF-8")
}
def base64encode(s: String) = {
Base64.encodeBase64String(s.getBytes("UTF-8"))
}
def encry(key: String, data: String) = {
val secret = new SecretKeySpec(key.getBytes, "HmacSHA1")
val mac = Mac.getInstance("HmacSHA1")
mac.init(secret)
val res = mac.doFinal(data.getBytes("UTF-8"))
res map { r => "%02x".format(r) } mkString ""
}
def get(ws: NingWSClient)(url: String, query: Map[String, String], header: Map[String, String]) = {
ws.url(url).withQueryString(query.toList: _*).withHeaders(header.toList: _*).get
}
}
,timestamp
,nonce
和sign
oauthHeader
我做了timestamp = 1482542041
nonce = 214129951907166
sign = YWQ2Y2VjNzJkOTQwY2JhYjEzYzgxZDM2YTg3ZGNlNjQ3ZjIzMDQ4Yw==
oauthHeader = OAuth oauth_consumer_key="AAA", oauth_nonce="214129951907166", oauth_signature="YWQ2Y2VjNzJkOTQwY2JhYjEzYzgxZDM2YTg3ZGNlNjQ3ZjIzMDQ4Yw%3D%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1482542041", oauth_token="CCC", oauth_version="1.0"
然后sbt compile
,得到了回复sbt run
。
我认为401 Authorization required
和val ws = NingWSClient()
之间没有问题:当我发送不需要OAuth 1.0的GET / POST请求(例如Google API)时,我成功了。
我还认为消费者密钥,消费者秘密,令牌,令牌秘密是正确的:当我在Ruby上运行类似的过程时,一切都很好。
我认为签名的过程是正确的,因为我一遍又一遍地在文档中检查过它。
所以,我认为编码或加密它们是错误的。 我不想使用Twitter4J库,因为我只是在研究Scala。
请告诉我这是什么问题。
答案 0 :(得分:0)
URLEncoder.encode
为' +'不是'%20',所以放replace("+", "%20")
。
加密变为:
val hmacShai = "HmacSHA1"
val keyStr = new SecretKeySpec(bytes(key), hmacShai)
val sig = {
val mac = Mac.getInstance(hmacShai)
mac.init(keyStr)
new String(base64encode(mac.doFinal(bytes(data))))
}