创建使用 extractCredentials 指令的自定义指令 - 值映射不是调用 extractCredentials 的成员
Creating a custom directive that uses extractCredentials directive - value map is not a member calling extractCredentials
我想创建一个自定义指令来包装一些路由,然后这将使内部路由能够访问 UserContext 对象(如果存在)。
authenticated { uc =>
post {
// ... can use uc object here
}
}
我遇到以下代码的编译时错误:
case class UserContext(username: String)
def authenticated: Directive1[Option[UserContext]] =
for {
credentials <- extractCredentials
result <- {
credentials match {
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => UserContext(c.token()) // authenticate(c.token)
case _ => None //rejectUnauthenticated(AuthenticationFailedRejection.CredentialsMissing)
}
}
} yield result
错误是:
value map is not a member of UserRoutes.this.UserContext
[error] credentials match {
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
我正在使用带有 bloop 的 VS Code,鼠标悬停错误显示:
value map is not a member of Product with java.io.Serializable
extractCredentials returns 一个 Option[HttpCredentials] 所以我不确定为什么我不能匹配它或映射它。
你在这里做什么:
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => UserContext(c.token()) // authenticate(c.token)
case _ => None //rejectUnauthenticated(AuthenticationFailedRejection.CredentialsMissing)
返回 UserContext
或 None
。一些编译器必须推断这两者之间的共同类型。每个 case class
或 case object
实现 Product with Serializable
因此它将是每两个 case
不实现其他公共共享超类型的实例的 LUB。
因此 result
右侧的内容将被推断为 Product with Serializable
而不是 Option[UserContext]
。 for
理解期望有 Option
和 map
,它可以调用 .map { result => result }
并且我们看到类型不匹配。
相信你想拥有这里
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => Some(UserContext(c.token()))
case _ => None
以防万一,提醒:Option
与Java中的@nullable
不一样,所以a: A
不会自动提升为Some(a): Option[A]
并且None
不同于 null
。
编辑:
另一件事是你有 flatMap 和 map 在 2 种不同的类型(指令和选项)上,所以你不能将它们组合成一个来理解。我假设你想做类似的事情:
extractCredentials.map { credentials =>
credentials.collect {
case c if c.scheme.equalsIgnoreCase("Bearer") => UserContext(c.token())
}
}
除了 Product with Serializable 的错误之外,您正在尝试创建指令。如果您使用 Some(UserContext) 修复代码,下一个错误是:
Error:(113, 14) type mismatch;
required: akka.http.scaladsl.server.Directive
编译器说当你对一个指令执行平面映射时,你需要return一个新的指令而不是一个选项。
此时你可以从一个函数创建指令 (Tuple1(Option[User) => Route) => Route .考虑到 Route 是 RequestContext => Future[RouteResult] like:
def authenticated: Directive1[Option[UserContext]] = {
extractCredentials.flatMap { credentials =>
Directive { inner =>
ctx => {
val result = credentials match {
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => Some(UserContext(c.token())) // authenticate(c.token)
case _ => None //rejectUnauthenticated(AuthenticationFailedRejection.CredentialsMissing)
}
inner(Tuple1(result))(ctx)
}
}
}
}
有了这个,你就有了一个使用 extractCredentials 的新指令 authenticated。
我想创建一个自定义指令来包装一些路由,然后这将使内部路由能够访问 UserContext 对象(如果存在)。
authenticated { uc =>
post {
// ... can use uc object here
}
}
我遇到以下代码的编译时错误:
case class UserContext(username: String)
def authenticated: Directive1[Option[UserContext]] =
for {
credentials <- extractCredentials
result <- {
credentials match {
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => UserContext(c.token()) // authenticate(c.token)
case _ => None //rejectUnauthenticated(AuthenticationFailedRejection.CredentialsMissing)
}
}
} yield result
错误是:
value map is not a member of UserRoutes.this.UserContext
[error] credentials match {
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
我正在使用带有 bloop 的 VS Code,鼠标悬停错误显示:
value map is not a member of Product with java.io.Serializable
extractCredentials returns 一个 Option[HttpCredentials] 所以我不确定为什么我不能匹配它或映射它。
你在这里做什么:
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => UserContext(c.token()) // authenticate(c.token)
case _ => None //rejectUnauthenticated(AuthenticationFailedRejection.CredentialsMissing)
返回 UserContext
或 None
。一些编译器必须推断这两者之间的共同类型。每个 case class
或 case object
实现 Product with Serializable
因此它将是每两个 case
不实现其他公共共享超类型的实例的 LUB。
因此 result
右侧的内容将被推断为 Product with Serializable
而不是 Option[UserContext]
。 for
理解期望有 Option
和 map
,它可以调用 .map { result => result }
并且我们看到类型不匹配。
相信你想拥有这里
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => Some(UserContext(c.token()))
case _ => None
以防万一,提醒:Option
与Java中的@nullable
不一样,所以a: A
不会自动提升为Some(a): Option[A]
并且None
不同于 null
。
编辑:
另一件事是你有 flatMap 和 map 在 2 种不同的类型(指令和选项)上,所以你不能将它们组合成一个来理解。我假设你想做类似的事情:
extractCredentials.map { credentials =>
credentials.collect {
case c if c.scheme.equalsIgnoreCase("Bearer") => UserContext(c.token())
}
}
除了 Product with Serializable 的错误之外,您正在尝试创建指令。如果您使用 Some(UserContext) 修复代码,下一个错误是:
Error:(113, 14) type mismatch;
required: akka.http.scaladsl.server.Directive
编译器说当你对一个指令执行平面映射时,你需要return一个新的指令而不是一个选项。
此时你可以从一个函数创建指令 (Tuple1(Option[User) => Route) => Route .考虑到 Route 是 RequestContext => Future[RouteResult] like:
def authenticated: Directive1[Option[UserContext]] = {
extractCredentials.flatMap { credentials =>
Directive { inner =>
ctx => {
val result = credentials match {
case Some(c) if c.scheme.equalsIgnoreCase("Bearer") => Some(UserContext(c.token())) // authenticate(c.token)
case _ => None //rejectUnauthenticated(AuthenticationFailedRejection.CredentialsMissing)
}
inner(Tuple1(result))(ctx)
}
}
}
}
有了这个,你就有了一个使用 extractCredentials 的新指令 authenticated。