2012-09-27 11 views
6

Sto tentando di autenticare gli utenti tramite il servizio di autenticazione remota. Ho scritto metodo di supporto per l'invio di un messaggio di servizio e di attesa per il risultato:Limitazione modulo riproduzione 1

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

Riporta Left[String] con una descrizione errore se il messaggio non può essere inviato, o non c'è risposta. Se la risposta del servizio ricevuto, restituisce Right[Option[User]]. Il servizio risponde con Option[User] in base al risultato dell'autenticazione.

per eseguire l'autenticazione effettiva Ho creato forma con un paio di validatori, eccolo:

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

Una cosa mi preoccupa di questo codice, si chiama authenticateAwait due volte. Significa che verranno inviati esattamente due messaggi per singola convalida. Quello di cui ho effettivamente bisogno, è di chiamare authenticateAwait una volta, memorizzare i risultati ed eseguire varie convalide su di esso. Sembra che non ci sia una soluzione semplice.

Per eseguire l'autenticazione, accedere ai campi modulo richiesti, significa che il modulo deve essere associato e quindi convalidato, ma non c'è modo di allegare errori al modulo esistente (sbaglio?).

Gli errori possono essere allegati al modulo solo durante la sua creazione, pertanto dovrei eseguire l'autenticazione nei validatori, ma il problema sopracitato si verifica.

La soluzione temporanea con cui sono arrivato è definire un metodo e un var al suo interno.

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

Questo è chiaramente un hack. Ci sono soluzioni migliori?

Aggiornamento: A mio parere, la forma dovrebbe sterilizzare solo ingresso, ma l'autenticazione deve essere eseguita in seguito al di fuori del modulo. Il problema è che gli errori vengono inviati alla vista come parte di Form ed è impossibile allegare errori al modulo esistente. Non esiste un modo semplice per creare un nuovo modulo con gli errori.

+1

si chiama AJAX; usalo e non creerai blocchi di codice ginormi cercando di risolvere un problema che non esiste (suggerimento: non è necessario creare un nuovo modulo) – virtualeyes

risposta

3

Quello che devi capire è che la Forma è immutabile. Ma c'è un metodo di utilità facile da usare per costruire un nuovo modulo con errori aggiunti:

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

sicuro, l'autenticazione conflittuale con la convalida semplifica semplicemente un'operazione. Di seguito non è stato verificato, ma questa è la direzione in cui vorrei entrare, proiezioni giuste filtrate attraverso una comprensione.

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

Gli esempi di riproduzione contengono l'autenticazione all'interno del blocco di verifica del modulo, quindi i verificatori sono un modo andare. Seguendo la tua soluzione, se l'autenticazione fallisce, come dovrei restituire il modulo con un errore di nuovo al modello? – lambdas

+0

lo fa già, la sinistra contiene un errore di convalida del modulo o un errore di connessione; Right contiene apparentemente l'utente ... comunque, basta avvolgerlo in un risultato, conflitto (Left (_)), u => Ok (Right (u)) – virtualeyes

+0

Inoltre, presumo dato che stai prendendo la rotta dei futures , quella prestazione è critica; come tale, in un'app web standard.ajax sarebbe la strada da percorrere, IMO - in questo modo non è necessario rieseguire la visualizzazione del modulo in caso di errore, l'utente non va mai da nessuna parte, ti basta occuparti della condizione di errore e visualizzarla, oppure restituire successo e gestire di conseguenza. – virtualeyes

Problemi correlati