Forms 第2局形式限制

Forms 第2局形式限制,forms,validation,scala,playframework,playframework-2.0,Forms,Validation,Scala,Playframework,Playframework 2.0,我正在尝试通过远程身份验证服务对用户进行身份验证。我已经编写了将消息发送到服务并等待结果的帮助器方法: def authenticateAwait(email: String, password: String ): Either[String, Option[User]] = { try { val future = authenticate(email, password)

我正在尝试通过远程身份验证服务对用户进行身份验证。我已经编写了将消息发送到服务并等待结果的帮助器方法:

def authenticateAwait(email:       String,
                      password:    String
                     ): Either[String, Option[User]] = {
  try {
    val future = authenticate(email, password)
    Right(Await.result(future, timeout.duration))
  } catch {
    case _ ⇒ Left("Unable to connect to authentication server")
  }
}
如果消息无法发送或没有响应,它将返回带有错误描述的
Left[String]
。如果收到服务响应,它将返回
Right[选项[用户]]
。服务根据身份验证结果使用选项[User]进行响应

为了执行实际的身份验证,我使用两个验证器创建了表单,如下所示:

val loginForm = Form(
  tuple(
    "email"    → email,
    "password" → nonEmptyText
  ) verifying ("Invalid email or password", result => result match {
    case (email, password) ⇒
      User.authenticateAwait(email, password) match {
        case Left(_) ⇒ true
        case Right(optUser) ⇒ optUser.isDefined
      }
  }) verifying ("Unable to connect to authentication server", result => result match {
    case (email, password) ⇒
      User.authenticateAwait(email, password) match {
        case Left(_) ⇒ false
        case Right(optUser) ⇒ true
      }
  })
)
这段代码让我担心的是,它调用了两次
authenticatewait
。这意味着每次验证将发送两条消息。我实际需要的是调用
authenticatewait
一次,存储结果并对其执行各种验证。似乎没有简单的解决办法

要执行身份验证,需要访问表单字段,这意味着应该绑定表单,然后对其进行验证,但无法将错误附加到现有表单(我错了吗?)

错误只能在表单创建期间附加到表单,因此我应该在验证器中执行身份验证,但随后出现上述问题

我附带的临时解决方案是定义一个方法和一个
var

def loginForm = {
  var authResponse: Either[String, Option[commons.User]] = null

  Form(
    tuple(
      "email"    → email,
      "password" → nonEmptyText
    ) verifying ("Invalid email or password", result ⇒ result match {
      case (email, password) ⇒
        authResponse = User.authenticateAwait(email, password)
        authResponse match {
          case Left(_) ⇒ true
          case Right(optUser) ⇒ optUser.isDefined
        }
    }) verifying ("Unable to connect to authentication server", result ⇒ result match {
      case (email, password) ⇒
        authResponse match {
          case Left(_) ⇒ false
          case Right(optUser) ⇒ true
        }
    })
  )
}
这显然是一种黑客行为。有没有更好的解决办法

更新: 在我看来,表单应该只清理输入,但稍后应该在表单之外执行身份验证。
问题是,错误作为
表单的一部分发送到视图,并且不可能将错误附加到现有表单。创建带有错误的新表单也没有简单的方法。

当然,将身份验证与验证混为一谈只会使简单的操作变得复杂。下面是未经测试的,但这是我将要走的方向,正确的投影通过一个过滤器过滤,以便理解

// point of validation is to sanitize inputs last I checked
val form = Form(tuple("email"→ email, "password"→ nonEmptyText)
val res = for{
  case(e,p) <- form.bindFromRequest.toRight("Invalid email or password")
  success   <- User.authenticateAwait(e,p).right 
} yield success
res fold( Conflict(Left(_)), u=> Ok(Right(u)) )
//验证点是对上次检查的输入进行清理
val form=表单(元组(“电子邮件”)→ 电子邮件,“密码”→ 非空文本)
val res=用于{

case(e,p)您必须理解的是表单是不可变的。但是有一种易于使用的实用方法可以构造一个新表单,并添加错误:

loginForm.copy(errors = Seq(FormError("email", "Already registered")))

播放示例在表单验证块中包含身份验证,因此验证程序是一种方法。按照您的解决方案,如果身份验证失败,我应该如何将带有错误的表单返回到模板?它已经在这样做了,左侧包含表单验证错误或连接错误;右侧显然包含用户…无论如何,只需将其总结为一个结果,Conflict(左()),u=>Ok(右(u))另外,我假设如果您选择的是未来路线,那么性能是至关重要的;因此,在标准的web应用程序中。ajax将是一条出路,IMO——这样就不需要在出错时重新显示表单,用户永远不会去任何地方,您只需处理错误条件并显示它,或者返回成功并相应地进行处理。这很简单称为AJAX;使用它,您就不会创建大量代码块来试图解决不存在的问题(提示:不需要创建新表单)