簡體   English   中英

如何在Scala Play 2.4.X中驗證OAuth簽名

[英]How can I verify an OAuth signature in Scala Play 2.4.X

為了與服務集成,我需要在Play 2.4(scala)服務器上實現REST端點。 該服務向我發送了一個GET請求,該請求已用他們給我的密鑰和秘密簽名。

我需要驗證請求是否來自他們

我的方法是:

val accessTokenOpt: Option[String] = request.headers.get(Security.AUTH_HEADER)
(accessTokenOpt, Security.consumer) match {
  case (Some(accessToken), Some(consumer)) => {
    val calculator = new OAuthCalculator(consumer, RequestToken("", ""))
    val expected = WS.url(s"http://${request.host}${request.uri}").sign(calculator)
    (expected.headers.get(Security.AUTH_HEADER), accessToken) match {
      case (Some(exp), Some(actual)) if exp == actual =>
        //good
      case (Some(exp), Some(actual)) =>
        //mismatch
      case (e, a) =>
        //missing tokens. :(
    }
  }
  case _ => //bad
}

可能出現問題expected.headers.(Security.AUTH_HEADER)返回None

我是否在代碼中缺少一些小東西,還是我的整個方法都不對?

我認為您的方法是正確的,並且從完全相同的參數計算得出的oauth簽名將始終匹配。 但是您必須考慮到您提到的一些參數,例如nonce和timestamp,為了做到這一點,我必須直接與執行簽名的Java類一起工作。

這是我設法使其工作的方式。 請記住,在我的情況下,與我的REST端點聯系的外部服務正在發送的Authorization標頭包含用於計算oauth_signature值的所有信息,但我擁有的oauth機密除外。

private def getProtocolFromRequest[T](request: Request[T]): String = {
  // To handle the case where a SSL offloading is involved
  request.headers.get(HeaderNames.X_FORWARDED_PROTO) match {
    case Some(forwardedProto: String) => forwardedProto
    case _ => if(request.secure) "https" else "http"
  }
}

def isOAuthSignatureValid[T](request:  Request[T]): Boolean = {
  request.headers.get(com.ning.http.client.oauth.OAuthSignatureCalculator.HEADER_AUTHORIZATION) match {
    case Some(authorizationHeaders) =>
      val AuthRegex = ".*oauth_nonce=\"([^\"]*)\".*oauth_signature=\"([^\"]*)\".*oauth_timestamp=\"([^\"]*)\".*".r

      authorizationHeaders match {
        case AuthRegex(nonce: String, providedSignature: String, timestamp: String) =>
          val signatureCalculator = new OAuthSignatureCalculator(new com.ning.http.client.oauth.ConsumerKey(oauthKey, oauthSecret), new com.ning.http.client.oauth.RequestToken(null, ""))
          val params = request.queryString.map(query => new Param(query._1, query._2.head)).toSeq
          val protocol = getProtocolFromRequest(request)
          val url = s"$protocol://${request.host}${request.path}"

          val expectedSignature = signatureCalculator.calculateSignature(
            request.method,
            Uri.create(url),
            timestamp.toInt,
            nonce,
            new util.ArrayList(),
            scala.collection.JavaConversions.seqAsJavaList(params)
          )
          expectedSignature.equals(URLDecoder.decode(providedSignature, "UTF-8"))
        case _ => false
      }
    case _ => false
  }
}

對我有用的流程如下:

  1. 抓住授權標頭
  2. 通過提供您的oauth使用者密鑰和秘密來創建OAuthSignatureCalculator。 就我而言,我沒有使用任何請求令牌。
  3. 從授權標頭中提取所需的oauth參數:簽名,隨機數,時間戳
  4. 使用OAuthSignatureCalculator來計算具有完全相同的隨機數和時間戳的簽名
  5. 將提供的簽名與計算出的簽名進行比較。 如果它們匹配,則對呼叫者進行身份驗證,否則,不進行身份驗證。

希望可以幫助到別人

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM