OAuth 是发布受保护数据并与之交互的一种简单方式。它是授与你访问权的更安全可靠的方式。例如,你可以通过它访问你在 Twitter 上的用户数据。
OAuth 有 2 个非常不同的版本:OAuth 1.0 和 OAuth 2.0。版本 2 非常简单,无需库和 helper 的支持。因此 Play 只提供 OAuth 1.0 的支持。
想用 OAuth,首先需要把 ws
库添加到你的 build.sbt
文件中:
libraryDependencies ++= Seq(
ws
)
OAuth 需要你将你的应用注册到服务提供方。确保检查了你提供的回调 URL,因为如果回调 URL 不匹配的话,服务提供方可能会拒绝你的调用。本地使用时,你可以在 /etc/hosts
中为本机伪造一个域名。
服务提供方会给你:
大部分事情都由 Play 的库完成。
现在你可以用访问令牌去访问受保护的用户数据了。
object Twitter extends Controller {
val KEY = ConsumerKey("xxxxx", "xxxxx")
val TWITTER = OAuth(ServiceInfo(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize", KEY),
true)
def authenticate = Action { request =>
request.getQueryString("oauth_verifier").map { verifier =>
val tokenPair = sessionTokenPair(request).get
// We got the verifier; now get the access token, store it and back to index
TWITTER.retrieveAccessToken(tokenPair, verifier) match {
case Right(t) => {
// We received the authorized tokens in the OAuth object - store it before we proceed
Redirect(routes.Application.index).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
}
}.getOrElse(
TWITTER.retrieveRequestToken("http://localhost:9000/auth") match {
case Right(t) => {
// We received the unauthorized tokens in the OAuth object - store it before we proceed
Redirect(TWITTER.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
})
}
def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
for {
token <- request.session.get("token")
secret <- request.session.get("secret")
} yield {
RequestToken(token, secret)
}
}
}
object Application extends Controller {
def timeline = Action.async { implicit request =>
Twitter.sessionTokenPair match {
case Some(credentials) => {
WS.url("https://api.twitter.com/1.1/statuses/home_timeline.json")
.sign(OAuthCalculator(Twitter.KEY, credentials))
.get
.map(result => Ok(result.json))
}
case _ => Future.successful(Redirect(routes.Twitter.authenticate))
}
}
}