为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?

Posted

技术标签:

【中文标题】为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?【英文标题】:Why does combining a custom WrappedRequest with extra type parameter and ActionFilter cause the type to be lost?为什么将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失? 【发布时间】:2016-01-06 15:49:31 【问题描述】:

将可将请求转换为自定义 WrappedRequestActionBuilder 与附加类型参数组合,然后将其与 ActionFilter 组合会导致自定义 WrappedRequest 的类型被删除。

为什么会这样?有解决办法吗?

例如,假设我需要一个身份验证 ActionBuilder 和一个可选的授权 ActionFilter,我们需要的用户类型可能会因使用情况而异。

查看这个人为的代码:

case class AuthRequest[A, U](val request: Request[A], val user: U) extends WrappedRequest[A](request)

case class TestUser(id: String)

case class AuthenticationAction[A]() extends ActionBuilder[(type λ[B] = AuthRequest[B, TestUser])#λ] 

  override def invokeBlock[A](request: Request[A], block: (AuthRequest[A, TestUser]) => Future[Result]): Future[Result] =
    block(AuthRequest(request, TestUser("test-id")))



case class AuthorisedAction[A]() extends ActionFilter[(type λ[B] = AuthRequest[B, TestUser])#λ] 

  // does some additional authorisation checks for added security
  def authorised(user: TestUser) = true

  override def filter[A](request: AuthRequest[A, TestUser]) = Future.successful 
    if( authorised(request.user) ) None
    else Some(Unauthorized)
  


请注意:上面的类型函数是this answer所必需的,因为AuthRequest上有额外的类型参数。这也是必需的,因为此 API 将用于不止一种类型的用户。

如果我再实现一个使用上述内容的控制器:

class ExampleController extends Controller 

  def secured = (AuthenticationAction() andThen AuthorisedAction())  request =>
    Ok(request.user.id)
  


我收到编译器错误 (value user is not a member of play.api.mvc.WrappedRequest[play.api.mvc.AnyContent])。也就是说,上面的变量request的类型是WrappedRequest,而不是预期的AuthRequest[play.api.mvc.AnyContent, TestUser]的类型!

我了解大多数用例 AuthenticationActionAuthorisedAction 将合并为一个操作,但由于授权是可选的,我希望将它们作为单独的关注点。

这可能吗?这是 Play Framework API 中的错误吗?还是 Scala 错误?还是人为错误?

【问题讨论】:

【参考方案1】:

使用您的示例,我能够编写如下操作:

class ExampleController extends Controller 
  def secured = AuthorisedAction().compose(AuthenticationAction())  request =>
    Ok(request.user.id)
  

有趣的是,在这两种情况下,IntelliJ 的类型检查都将request 视为AuthRequest[AnyContent, TestUser] 类型——只有scalac 将其视为WrappedRequest

【讨论】:

以上是关于为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?的主要内容,如果未能解决你的问题,请参考以下文章

Java 9:将自定义模块化运行时映像与第三方插件系统相结合

为啥委托方法需要将自定义类托管对象上下文的内容保存在委托类托管对象上下文中?

向 ModelAdmin 表单添加额外字段

将自定义元素添加到 ngRepeat 列表

将自定义组件添加到 EXTJS 图表

将自定义操作添加到 UserModel 的管理页面