2012-09-27 64 views
6

我試圖通過遠程驗證服務來驗證用戶。我寫的輔助方法來發送消息給服務,並等待結果:播放2格式限制

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[Option[User]]。服務根據驗證結果以Option[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 
     } 
    }) 
) 

有一件事我擔心這段代碼,它調用authenticateAwait兩次。這意味着每個驗證只會發送兩條消息。我真正需要的是調用authenticateAwait一次,存儲結果並對其執行各種驗證。似乎沒有簡單的解決方案。

要執行身份驗證,需要訪問表單字段,這意味着應該綁定表單然後進行驗證,但是沒有辦法將錯誤附加到現有表單(我錯了嗎?)。

錯誤只能在創建時附加到表單上,所以我應該在驗證器中執行驗證,但是會出現上述問題。

我附帶的臨時解決方案是在裏面定義一個方法和一個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 
     } 
    }) 
) 
} 

這顯然是一種破解。有沒有更好的解決方案?

更新: 在我看來,窗體應該只對輸入進行消毒,但認證應該稍後在窗體外進行。 問題是,錯誤作爲Form的一部分發送到視圖,並且不可能將錯誤附加到現有表單。有沒有簡單的方法來創建新的表單也有錯誤。

+1

它被稱爲AJAX;使用它,你不會創建ginormous代碼塊試圖解決不存在的問題(提示:不需要創建一個新的表單) – virtualeyes

回答

3

你必須明白的是,Form是不可變的。但有一個易於使用的實用方法來構建一個新的表單,添加錯誤:

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

當然,將驗證與驗證相混淆只是使一個簡單的操作變得複雜。下面是未經測試的,但這是我將要進入的方向,正確的投影通過理解過濾。

// 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))) 
+0

播放樣本包含驗證表單驗證塊內,因此驗證是一種方式去。遵循您的解決方案,如果身份驗證失敗,我應該如何將錯誤返回給模板? – lambdas

+0

它已經這樣做了,左側包含表單驗證錯誤或連接錯誤; Right顯然包含了用戶...無論如何,只是將它包含在Result,Conflict(Left(_)),u => Ok(Right(u)) – virtualeyes

+0

中,我假設您正在採用期貨路線,這一表現至關重要;因此,在一個標準的網絡應用程序。ajax應該是要走的路 - 國際海事組織 - 這樣就不需要重新顯示錯誤形式,用戶永遠不會去任何地方,只需處理錯誤情況並顯示它,或者返回成功並相應處理。 – virtualeyes