文档

§OAuth

OAuth 是一种简单的方式来发布和交互受保护的数据。它也是人们授予您访问权限的安全可靠方式。例如,它可以用于访问您用户在 Twitter 上的数据。

OAuth 有两个截然不同的版本:OAuth 1.0OAuth 2.0。版本 2 足够简单,可以在没有库或帮助程序的情况下轻松实现,因此 Play 仅提供对 OAuth 1.0 的支持。

§用法

要使用 OAuth,首先将 ws 添加到您的 build.sbt 文件中

libraryDependencies ++= Seq(
  ws
)

§所需信息

OAuth 要求您将应用程序注册到服务提供商。确保检查您提供的回调 URL,因为如果它们不匹配,服务提供商可能会拒绝您的调用。在本地工作时,您可以使用 /etc/hosts 在本地机器上伪造一个域名。

服务提供商将为您提供

§身份验证流程

大部分流程将由 Play 库完成。

  1. 从服务器获取请求令牌(在服务器到服务器的调用中)
  2. 将用户重定向到服务提供商,用户将在那里授权您的应用程序使用其数据
  3. 服务提供商将把用户重定向回来,并提供一个 /验证器/
  4. 使用该验证器,将 /请求令牌/ 交换为 /访问令牌/(服务器到服务器的调用)

现在,/访问令牌/ 可以传递给任何访问受保护数据的调用。

有关 OAuth 流程的更多详细信息,请访问 The OAuth Bible

§示例

要在控制器中实现流程,请定义密钥和消费者密钥,并检索令牌和密钥

val KEY = ConsumerKey("xxxxx", "xxxxx")

val oauth = 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 sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
  for {
    token  <- request.session.get("token")
    secret <- request.session.get("secret")
  } yield {
    RequestToken(token, secret)
  }
}

def authenticate = Action { (request: Request[AnyContent]) =>
  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
      oauth.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(oauth.retrieveRequestToken("https://localhost:9000/auth") match {
      case Right(t) => {
        // We received the unauthorized tokens in the OAuth object - store it before we proceed
        Redirect(oauth.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
      }
      case Left(e) => throw e
    })
}

实现流程后,可以通过通过 WS 签署请求来获取时间线

def timeline = Action.async { implicit request: Request[AnyContent] =>
  sessionTokenPair match {
    case Some(credentials) => {
      wsClient
        .url("https://api.twitter.com/1.1/statuses/home_timeline.json")
        .sign(OAuthCalculator(KEY, credentials))
        .get()
        .map(result => Ok(result.json))
    }
    case _ => Future.successful(Redirect(routes.Application.authenticate))
  }
}

注意:OAuth 不会提供任何针对 MITM 攻击的保护。此示例显示了存储在会话 cookie 中的 OAuth 令牌和密钥 - 为了获得最佳安全性,请始终使用 HTTPS,并定义 play.http.session.cookie.secure=true

下一步:与 Pekko 集成


发现此文档中的错误?此页面的源代码可以在 此处 找到。阅读完 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?请访问 我们的社区论坛,与社区开始对话。