Ошибка аутентификации JWT в Akka HTTP Scala: ‘Ни один из перегруженных вариантов метода decode’

Вопрос или проблема

Я пытаюсь добавить аутентификацию JWT в своё API приложения на Akka HTTP Scala.

Я использую зависимости Maven jwt-circe и jwt-core из репозитория Maven.

Однако текущий код вызывает ошибки типов:

case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256))

Ошибка типа: ни один из перегруженных альтернатив метода isValid в трейте JwtCore с типами.

onComplete(Jwt.decode(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)))

Ошибка типа: ни один из перегруженных альтернатив метода decode в трейте JwtCore с типами.

Снова, я установил обе зависимости jwt-circe и jwt-core (проверьте код sbt).

Не могли бы вы помочь мне определить проблему?

Заранее спасибо!

Мой текущий код выглядит следующим образом:

Классы:


final case class Account(name: String, age: Int, country: String, roles: List[String])

object JsonFormats {
import DefaultJsonProtocol._

implicit val accountFormat: RootJsonFormat[Account] = jsonFormat4(Account.apply)

Код JWT:


import pdi.jwt.{ Jwt, JwtAlgorithm, JwtClaim, JwtCirce }

private val expiresIn = 1 * 24 * 60 * 60
implicit val clock: Clock = Clock.systemUTC
private val secretKey = "vp-akka-http-jwt"

def authenticated: Directive1[Account] =
  optionalHeaderValueByName("Authorization").flatMap {
    case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) =>
         getClaims(jwtToken) match {
           case Some(account) => provide(account)
           case None => reject(AuthorizationFailedRejection).toDirective[Tuple1[Account]]
         }
    case t => println(t.get)
           complete(StatusCodes.Unauthorized)
}

private def getClaims(jwtToken: String): Option[Account] = {
    onComplete(Jwt.decode(jwtToken, secretKey, Seq(JwtAlgorithm.HS256))){
       case Success(value) => 
            Some(value.content.parseJson.convertTo[Account])
       case Failure(ex) => None
    }            
}

Конфигурация SBT:


lazy val akkaHttpVersion = "10.6.3"
lazy val akkaVersion    = "2.9.4"

resolvers += "Akka library repository".at("https://repo.akka.io/maven")

fork := true

lazy val root = (project in file(".")).
  settings(
    inThisBuild(List(
      organization    := "com.example",
      scalaVersion    := "3.3.3"
    )),
    name := "eskimi-bidding-agent",
    libraryDependencies ++= Seq(
      // ....
      ("com.github.jwt-scala"     %% "jwt-circe"             % "10.0.1")
         .exclude("io.circe", "circe-parser_3")
         .exclude("io.circe", "circe-core_3")
         .exclude("org.typelevel", "cats-kernel_3")
         .exclude("org.typelevel", "cats-core_3")
         .exclude("io.circe", "circe-numbers_3")
         .exclude("org.typelevel", "jawn-parser_3")
         .exclude("io.circe", "circe-jawn_3"),
      "com.github.jwt-scala"     %% "jwt-core"             % "10.0.1",
      // ....
    )
  )

Ответ или решение

Чтобы решить вашу проблему с ошибками типа, связанными с методами isValid и decode в библиотеке JWT для Scala, давайте сначала проверим, правильно ли вы используете эти методы и соответствующие зависимости.

Ошибка и ее причины

Ваши ошибки связаны с тем, что вы пытаетесь использовать методы isValid и decode, которые требуют различных типов аргументов. Основные причины могут быть в следующем:

  1. Неправильные параметры: Убедитесь, что вы передаете правильные параметры в методы.
  2. Несоответствие типов: Вероятно, проблема в том, что передаваемые вами значения не соответствуют ожидаемым типам методов.

Шаги для исправления

  1. Проверьте зависимости:
    Убедитесь, что вы используете совместимые версии библиотек. В вашем примере вы используете jwt-circe и jwt-core версии 10.0.1, которые должны быть совместимы между собой.
"com.github.jwt-scala" %% "jwt-core" % "10.0.1"
"com.github.jwt-scala" %% "jwt-circe" % "10.0.1"
  1. Измените код аутентификации:

    • Убедитесь, что вы передаете правильные аргументы в методы isValid и decode. Вот исправленный код:
import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim, JwtCirce}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directive1
import scala.util.{Success, Failure}

private val secretKey = "vp-akka-http-jwt"

def authenticated: Directive1[Account] =
  optionalHeaderValueByName("Authorization").flatMap {
    case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) =>
      getClaims(jwtToken) match {
        case Some(account) => provide(account)
        case None => reject(AuthorizationFailedRejection)
      }
    case _ => complete(StatusCodes.Unauthorized)
  }

private def getClaims(jwtToken: String): Option[Account] = {
  Jwt.decode(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) match {
    case Success(claim) => Some(claim.content.parseJson.convertTo[Account])
    case Failure(_) => None
  }
}
  1. Проверьте парсинг JSON:
    Убедитесь, что ваш класс Account и его формат JSON корректно определены. Возможно, вам нужно добавить имплицитное преобразование для Account в JsonFormats, если вы это еще не сделали (как показано в вашем исходном коде).

Итоговый код:

Вот окончательный вариант вашего кода с учетом вышеуказанных правок:

import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim, JwtCirce}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model.StatusCodes
import scala.util.{Success, Failure}
import spray.json._

final case class Account(name: String, age: Int, country: String, roles: List[String])

object JsonFormats {
  import DefaultJsonProtocol._
  implicit val accountFormat: RootJsonFormat[Account] = jsonFormat4(Account)
}

private val secretKey = "vp-akka-http-jwt"

def authenticated: Directive1[Account] =
  optionalHeaderValueByName("Authorization").flatMap {
    case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) =>
      getClaims(jwtToken) match {
        case Some(account) => provide(account)
        case None => reject(AuthorizationFailedRejection)
      }
    case _ => complete(StatusCodes.Unauthorized)
  }

private def getClaims(jwtToken: String): Option[Account] = {
  Jwt.decode(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) match {
    case Success(claim) => Some(claim.content.parseJson.convertTo[Account])
    case Failure(_) => None
  }
}

Заключение

После выполнения указанных действий ваша проблема с аутентификацией JWT в Akka HTTP должна быть решена. Убедитесь, что вы также протестировали свою логику аутентификации, чтобы гарантировать правильное поведение вашего API. Если появятся новые ошибки, проверьте стек-трейсы, чтобы лучше понять, из-за чего они возникают, и устранить причины.

Оцените материал
Добавить комментарий

Капча загружается...