繁体   English   中英

使用Scala / Play Framework 2.7.x解码Cookie字符串

[英]Decode Cookie String with Scala/Play Framework 2.7.x

好。

因此,在scala / play框架中解码Cookie的正常方法是这样的:

 def admin_scrape[T]:Action[AnyContent] = Action.async {request: Request[AnyContent] => Future {
      println("****************************")
      println("inside admin_scrape")
      println("****************************")
      val body: AnyContent          = request.body
      val jsonBody: Option[JsValue] = body.asJson
      var texts_update: String = "";
      var article_url_update: String = "";
      jsonBody
      .map{json =>  
        println("value of json")
        println(json)
        request.session
        .get("access_rights") //access_rights is the token name in the cookie string I set
        .map{access_rights =>
        <...>

但是,我想在Play中使用套接字。

不幸的是,播放框架的Web套接字支持( https://www.playframework.com/documentation/2.7.x/ScalaWebSockets )明确支持类似于流的结构,并且数据流在前端启动。 不敲它们,也许这是一个设计选择,但是我也希望在套接字中插入能够在后端实例化的请求。 所以我使用了这个( https://github.com/TooTallNate/Java-WebSocket )获得惯用的套接字支持。

这可行。

但是,请考虑以下因素(它可以正常工作):

override def onOpen(conn: WebSocket, handshake: ClientHandshake): Unit = {
    conn.send("Welcome to the server client!")
    broadcast("new connection everyone: " + handshake.getResourceDescriptor)
    var cookie = "no cookie"
    if(handshake.hasFieldValue("Cookie")){
      println("We found a cookie")
      var cookie = handshake.getFieldValue("Cookie");
      println("value of cookie")
      println(cookie)
      // the following CODE_BLOCK does not work
      // and gives the error:
      // [error] /Users/patientplatypus/Documents/platypusNEST/the_daily_blech/scala_blech_blog/blog/app/sockets/SocketServer.scala:86:32: value decode is not a member of object play.api.mvc.Cookies
      // [error]       val decode_val = Cookies.decode(cookie)
      // [error]                                ^
      // *CODE_BLOCK*
      // val decode_val = play.api.mvc.Cookies.decode(cookie)
      // println("value of decode_val")
      // println(decode_val)
      // *CODE_BLOCK*
      // reasoning - I need a way to get the cookie string into a mapping and this seemed likely.
    }else{
      println("We did not find a cookie")
    }
    <...>

当我从具有客户端Cookie的应用程序运行此程序时,我成功在服务器上打印了:

We found a cookie
value of cookie
PLAY_SESSION=SUPERDUPERLONGHASHSTRING

我需要能够像处理请求一样将此哈希字符串转换回映射,但是我无法找到正确的解码。 上面进行了尝试,但我意识到我已经在阅读Play框架2.0的文档( https://www.playframework.com/documentation/2.0/api/scala/play/api/mvc/Cookies $ .html)。 我想知道当前的2.7.x版本中是否存在某种解码功能,或者如何将该哈希字符串转换回cookie映射。

编辑:

目前,最相关的文件似乎是https://www.playframework.com/documentation/2.7.x/api/scala/play/api/mvc/Cookies $ html的,特别是decodeCookieHeaderdecodeSetCookieHeader ,因为他们有一个字符串和根据每种方法的类型签名,返回一个Cookies序列。 但是,跑步

var cookiesDecodeCookieHeader = Cookies.decodeCookieHeader(cookie)
println("value of cookiesDecodeCookieHeader: ")
println(cookiesDecodeCookieHeader)
var cookiesDecodeSetCookieHeader = Cookies.decodeSetCookieHeader(cookie)
println("value of cookiesDecodeSetCookieHeader: ")
println(cookiesDecodeSetCookieHeader)

给我

value of cookiesDecodeCookieHeader: 
List()
value of cookiesDecodeSetCookieHeader: 
List()

因此,这是不正确的。

编辑编辑:

同样

var cookiesFromCookieHeader = Cookies.fromCookieHeader(Some(cookie.toString))
  println("value of cookiesFromCookieHeader: ")
  println(cookiesFromCookieHeader)
  var cookiesFromSetCookieHeader = Cookies.fromSetCookieHeader(Some(cookie.toString))
  println("value of cookiesFromSetCookieHeader: ")
  println(cookiesFromSetCookieHeader)

结果为空地图。 此时,我的解决方案似乎集中于随机浏览手册页( https://www.playframework.com/documentation/2.7.x/api/scala/play/api ),因此我打开了一个有关在游戏github上进行澄清的问题:( https://github.com/playframework/playframework/issues/9837 )。

如果有人有任何想法,请告诉我。 谢谢!

编辑编辑编辑:

我已经到了研究其他JWT库的地步,因为显然play不能按我需要的方式工作:<。 我看过https://github.com/pauldijou/jwt-scala/ ,但它似乎不适用于最新版本的播放器(请参阅此处: https : //github.com/pauldijou/jwt- scala / issues / 153 )。 我也看过像这样的东西(看起来很好,很整洁) https://dzone.com/articles/jwt-authentication-with-play-framework ,但是它们使用的库已被弃用。

哇,这不应该那么难。 任何建议,将不胜感激。

我设法通过在此处找到的play framework备份Cookies.scala文件来弄清楚( https://github.com/playframework/playframework/blob/2.7.x/core/play/src/main/scala/play /api/mvc/Cookie.scala )。 这比我认为仅应该解析会话cookie数据(主要是要知道在哪里查找)要困难得多,因此我不必导入随机库。 这也是使用java-websocket包的示例,它比play framework方法更为习惯。 我正在发布整个文件(很小),以便可以看到所有导入和逻辑。

如果您尝试自己实现此目的,则应该找到以下输出:

value of jws.getBody.asScala.toMap: 
Map(data -> {your_cookie_key=your_cookie_value, csrfToken=SUPER-SECRET-LONGHASH}, 
     nbf -> SECRETNUM, iat -> SECRETNUM)

在您的终端中。

再次感谢所有愿意提供帮助的人。

package sockets

import play.api.libs.json._
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.net.InetSocketAddress
import java.net.UnknownHostException
import java.nio.ByteBuffer
import org.java_websocket.WebSocket
import org.java_websocket.WebSocketImpl
import org.java_websocket.framing.Framedata
import org.java_websocket.handshake.ClientHandshake
import org.java_websocket.server.WebSocketServer

import javax.inject._
import play.api.libs.json._
import play.api._
import play.api.mvc._
import play.api.http._

import scala.collection.JavaConverters._

import io.jsonwebtoken.Jwts
import io.jsonwebtoken._

import java.nio.charset.StandardCharsets
import java.time.Clock
import java.util.{ Base64, Date, Locale }


@Singleton
class SocketServer @Inject()() extends WebSocketServer(new InetSocketAddress(8887)){


  def parse(encodedString: String): Map[String, AnyRef] = {
    println("inside parse def and value of encodedString: ", encodedString)
    println("***************")
    println("***************")
    println("***************")

    var newEncodedString = encodedString.slice(13, encodedString.length)
    println("value of newEncodedString")
    println(newEncodedString)
    println("***************")
    println("***************")
    println("***************")

    def jwtConfiguration = new JWTConfiguration();

    val jwtClock = new io.jsonwebtoken.Clock {
      val clock = Clock.systemDefaultZone().instant()
      override def now(): Date = java.util.Date.from(clock)
    }

    val base64EncodedSecret: String = {
      Base64.getEncoder.encodeToString(
        "hellotheresailor".getBytes(StandardCharsets.UTF_8) //note that this secret should ideally be set in your application.conf file and imported via injection
      )
    }

    val jws: Jws[Claims] = Jwts.parser()
      .setClock(jwtClock)
      .setSigningKey(base64EncodedSecret)
      .setAllowedClockSkewSeconds(jwtConfiguration.clockSkew.toSeconds)
      .parseClaimsJws(newEncodedString)

    val headerAlgorithm = jws.getHeader.getAlgorithm
    if (headerAlgorithm != jwtConfiguration.signatureAlgorithm) {
      val id = jws.getBody.getId
      val msg = s"Invalid header algorithm $headerAlgorithm in JWT $id"
      throw new IllegalStateException(msg)
    }

    println("value of jws.getBody.asScala.toMap: ")
    println(jws.getBody.asScala.toMap)

    jws.getBody.asScala.toMap
  }

  override def onOpen(conn: WebSocket, handshake: ClientHandshake): Unit = {
    conn.send("Welcome to the server!")
    broadcast("new connection: " + handshake.getResourceDescriptor)
    var cookie = "no cookie"
    if(handshake.hasFieldValue("Cookie")){
      println("We found a cookie")
      var cookie = handshake.getFieldValue("Cookie");
      println("value of cookie")
      println("parsedCookie: ")
      val parsedCookie = parse(cookie)
      println(parsedCookie)
    }else{
      println("We did not find a cookie")
    }
    println(
      conn.getRemoteSocketAddress.getAddress.getHostAddress +
        " entered the room!")
  }

  override def onClose(conn: WebSocket,
                       code: Int,
                       reason: String,
                       remote: Boolean): Unit = {
    broadcast(conn + " has left the room!")
    println(conn + " has left the room!")
  }

  override def onMessage(conn: WebSocket, message: String): Unit = {
    broadcast(message)
    println(conn + "we heard: " + message)
  }

  override def onMessage(conn: WebSocket, message: ByteBuffer): Unit = {
    broadcast(message.array())
    println(conn + "we heard: " + message)
  }

  override def onError(conn: WebSocket, ex: Exception): Unit = {
    ex.printStackTrace()
    if (conn != null) {}
  }

  override def onStart(): Unit = {
    println("Server started!")
    setConnectionLostTimeout(0)
    setConnectionLostTimeout(100)
  }

}

因此,在您从Cookie检索值的示例中,您似乎实际上是在谈论检索会话值( request.session.get(...) )。

不幸的是,播放框架的Web套接字支持( https://www.playframework.com/documentation/2.7.x/ScalaWebSockets )明确支持类似于流的结构,并且数据流在前端启动。

我不确定您的意思,Play绝对有可能在Websocket通信中发送第一条消息。

来自Play websockets文档

import play.api.mvc._
import akka.stream.scaladsl._

def socket = WebSocket.accept[String, String] { request =>
  // Just ignore the input
  val in = Sink.ignore

  // Send a single 'Hello!' message and close
  val out = Source.single("Hello!")

  Flow.fromSinkAndSource(in, out)
}

这是一个非常简单的示例,它将返回"Hello!" 建立连接后,将消息发送给websocket客户端。

此处理代码还可以直接访问request: RequestHeader ,这意味着您可以直接从那里直接从会话中获取内容,而无需解码任何cookie:

  def ws = WebSocket.accept { request =>

    request.session.get("access_rights") match {
      case Some(value) =>
        println("We found access_rights!")
        println("value of access_rights")
        println(value)
      case None =>
        println("We did not find access_rights!")
    }

    val in = Sink.ignore
    val out = Source.single("Welcome to the server client!")
    Flow.fromSinkAndSource(in, out)
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM