2012-09-27 11 views
6

Ich versuche, Benutzer über Remote-Authentifizierungsdienst zu authentifizieren. Ich habe für das Senden von Nachricht an Service-Helfer-Methode geschrieben und warten auf Ergebnis:Play 2 Formular Einschränkung

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") 
    } 
} 

Es gibt Left[String] mit einer Fehlerbeschreibung, wenn die Nachricht nicht gesendet werden kann, oder es gibt keine Antwort. Wenn die Serviceantwort empfangen wurde, wird Right[Option[User]] zurückgegeben. Der Dienst antwortet mit Option[User] abhängig vom Authentifizierungsergebnis.

eigentliche Authentifizierung auszuführen I Form mit ein paar Validatoren erstellt haben, hier ist es:

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 
     } 
    }) 
) 

Eine Sache, mir diesen Code Sorgen, nennt es authenticateAwait zweimal. Es bedeutet, dass genau zwei Nachrichten pro einzelne Validierung gesendet werden. Was ich wirklich brauche, ist, einmal die Nummer authenticateAwait aufzurufen, das Ergebnis zu speichern und verschiedene Validierungen durchzuführen. Es scheint, dass es keine einfache Lösung gibt.

Um die Authentifizierung durchzuführen, müssen Sie auf die erforderlichen Formularfelder zugreifen, dh das Formular muss gebunden und dann validiert werden, aber es gibt keine Möglichkeit, Fehler an das vorhandene Formular anzuhängen (irre ich?).

Fehler können dem Formular nur während seiner Erstellung hinzugefügt werden, daher sollte ich Authentifizierung in den Validatoren durchführen, aber dann tritt das zuvor genannte Problem auf.

Die vorübergehende Lösung, mit der ich kam, ist eine Methode und eine var darin zu definieren.

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 
     } 
    }) 
) 
} 

Dies ist eindeutig ein Hack. Gibt es bessere Lösungen?

Update: Meiner Meinung nach Formular sollte nur Eingabe bereinigen, aber die Authentifizierung sollte später außerhalb des Formulars durchgeführt werden. Das Problem ist, dass Fehler an die Ansicht als Teil der Form gesendet werden und es ist unmöglich, Fehler an das vorhandene Formular anzuhängen. Es gibt keine einfache Möglichkeit, ein neues Formular mit Fehlern zu erstellen.

+1

es heißt AJAX; Verwenden Sie es und Sie werden keine ginormous Codeblöcke erstellen, die versuchen, ein Problem zu lösen, das nicht existiert (Hinweis: es besteht keine Notwendigkeit, ein neues Formular zu erstellen) – virtualeyes

Antwort

3

Was Sie verstehen müssen, ist, dass Form unveränderlich ist. Aber es gibt eine einfach zu bedienende Utility-Methode, um ein neues Formular mit Fehlern zu erstellen:

0

die Zusammenführung der Authentifizierung mit der Validierung macht eine einfache Operation zu einem komplexen Vorgang. Unten ist ungeprüft, aber das ist die Richtung, in die ich gehen würde, rechte Projektionen, die durch ein Verständnis gefiltert werden.

// 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

Play-Beispiele enthalten Authentifizierung im Formularprüfblock, daher ist Verifier ein Weg gehen. Wie kann ich bei einer fehlgeschlagenen Authentifizierung nach Ihrer Lösung ein Formular mit einem Fehler an die Vorlage zurücksenden? – lambdas

+0

macht es bereits, die linke enthält entweder Formularüberprüfungsfehler oder Verbindungsfehler; Richtig enthält den Benutzer anscheinend ... sowieso, hülle es einfach in ein Ergebnis, Konflikt (Links (_)), u => Ok (Rechts (u)) – virtualeyes

+0

auch, vorausgesetzt, dass du die Futures-Route nimmst , diese Leistung ist kritisch; als solche, in einer Standard-Web-App.Ajax wäre der Weg zu gehen, IMO - auf diese Weise gibt es keine Notwendigkeit, das Formular im Fehlerfall wieder anzuzeigen, Benutzer geht nirgendwo hin, Sie nur mit der Fehlerbedingung beschäftigen und anzuzeigen, oder Erfolg zurück und behandeln entsprechend. – virtualeyes