OAuth
OAuth 是发布受保护数据及与之交互的一种简单方式。它授权访问的更安全可靠的方式。例如, 可以用它访问你在Twitter上的用户数据。
有二种不同版本的OAuth: OAuth 1.0 和 OAuth 2.0。版本 2 非常简单,无需库和助手, 所以Play仅提供 OAuth 1.0支持。
用法
要使用OAuth, 首先添加ws
到你的build.sbt
文件:
libraryDependencies ++= Seq(
ws
)
需要的信息
OAuth 需要你注册你的应用程序到服务提供方。确保检查了你提供的回调URL, 因为如果不匹配的话,服务提供方可能会拒绝你的调用。在本地使用时,你可以在 /etc/hosts
中为本机伪造一个域名。
服务提供方会给你:
- 应用程序 ID
- 安全密钥
- 请求令牌 URL
- 访问令牌 URL
- 授权 URL
验证流程
大部分工作流由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))
}
}
}