文件

§OAuth

OAuth 是一種公開和互動受保護資料的簡單方式。它也是人們授予您存取權限更安全的方法。例如,它可用於存取您使用者在 Twitter 上的資料。

OAuth 有兩個截然不同的版本:OAuth 1.0OAuth 2.0。版本 2 夠簡單,可以輕鬆實作,無需使用函式庫或輔助程式,因此 Play 僅提供對 OAuth 1.0 的支援。

§使用方式

要使用 OAuth,請先將 ws 新增到 build.sbt 檔案

libraryDependencies ++= Seq(
  ws
)

§所需資訊

OAuth 需要您向服務供應商註冊您的應用程式。務必檢查您提供的回呼網址,因為如果服務供應商的網址與您提供的網址不符,服務供應商可能會拒絕您的呼叫。在本地端工作時,您可以使用 /etc/hosts 在您的本地端機器上偽造一個網域。

服務供應商會提供給您

§驗證流程

大部分的流程都將由 Play 函式庫完成。

  1. 從伺服器取得要求權杖(在伺服器對伺服器的呼叫中)
  2. 將使用者重新導向到服務供應商,使用者將在那裡授予您的應用程式使用其資料的權限
  3. 服務供應商將重新導向使用者,並提供給您一個 /驗證者/
  4. 使用該驗證者,將 /要求權杖/ 交換成 /存取權杖/(伺服器對伺服器的呼叫)

現在,/存取權杖/ 可以傳遞給任何呼叫,以存取受保護的資料。

可以在 OAuth 聖經 中找到有關 OAuth 程序流程的更多詳細資訊。

§範例

要在控制器中實作流程,請定義金鑰和消費者金鑰,並擷取權杖和金鑰

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://127.0.0.1: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 整合


在這個文件裡發現錯誤嗎?這個頁面的原始碼可以 在此找到。在閱讀完 文件指南 後,請隨時提交拉取請求。有任何問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開討論。