2012-09-27 16 views
6

Próbuję uwierzytelnić użytkowników za pomocą usługi zdalnego uwierzytelniania. Pisałem metody pomocnika do wysyłania wiadomości do służby i czeka na wynik:Odtwórz 2 ograniczenia formularza

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

Zwraca Left[String] wraz z opisem usterki, jeśli wiadomość nie może zostać wysłana, lub nie ma odpowiedzi. Jeśli otrzymana odpowiedź serwisowa zwróci Right[Option[User]]. Usługa odpowiada Option[User] w zależności od wyniku uwierzytelnienia.

Aby wykonać rzeczywistą uwierzytelniania Mam utworzony formularz z kilkoma walidatorami, tutaj jest:

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

Jedno mnie martwi o tym kodzie, wywołuje authenticateAwait dwukrotnie. Oznacza to, że dokładnie dwie wiadomości zostaną wysłane na pojedynczą walidację. To, czego potrzebuję, to jednorazowe wywołanie authenticateAwait, zapisanie wyniku i wykonanie różnych walidacji. Wydaje się, że nie ma prostego rozwiązania.

Aby wykonać uwierzytelnianie, dostęp do wymaganych pól formularza, oznacza to, że formularz powinien zostać powiązany, a następnie zweryfikowany, ale nie ma możliwości dołączenia błędów do istniejącego formularza (czy jestem w błędzie?).

Błędy mogą być dołączone do formularza tylko podczas jego tworzenia, dlatego należy wykonać uwierzytelnianie w walidatorach, ale pojawia się wspomniany wyżej problem.

Tymczasowe rozwiązanie, z którym się zetknąłem, to zdefiniowanie w nim metody i 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 
     } 
    }) 
) 
} 

To jest najwyraźniej hack. Czy są jakieś lepsze rozwiązania?

Aktualizacja: Moim zdaniem forma powinna tylko zdezynfekować wejście, ale autoryzacja powinna być wykonywana później poza formę. Problem polega na tym, że błędy są wysyłane do widoku jako część Form i nie można dołączyć błędów do istniejącego formularza. Nie ma prostego sposobu na tworzenie nowej formy z błędami.

+1

nazywa się AJAX; użyj go i nie utworzymy potężnych bloków kodu próbujących rozwiązać problem, który nie istnieje (podpowiedź: nie ma potrzeby tworzenia nowego formularza) – virtualeyes

Odpowiedz

3

To, co musisz zrozumieć, to że Forma jest niezmienna. Jest jednak prosta w użyciu metoda użyteczna do skonstruowania nowego formularza z dodanymi błędami:

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

Oczywiście, łączenie uwierzytelniania z walidacją powoduje złożenie prostej operacji. Poniżej jest nietestowany, ale to jest kierunek, w którym chciałbym wejść, odpowiednie projekcje filtrowane przez do zrozumienia.

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

Odtwarzaj próbki zawierają uwierzytelnianie wewnątrz bloku weryfikacji formularza, dlatego weryfikatory są sposobem iść. Podążając za rozwiązaniem, jeśli uwierzytelnienie nie powiedzie się, w jaki sposób powinienem zwrócić formularz z błędem z powrotem do szablonu? – lambdas

+0

to już robi, lewy zawiera błąd sprawdzania poprawności formularza lub błąd połączenia; Prawo zawiera użytkownika najwyraźniej ... w każdym razie, po prostu zapakuj go w Wynik, Konflikt (lewy (_)), u => OK (prawy (u)) – virtualeyes

+0

również, zakładam, że bierzesz drogę przyszłości , wydajność jest krytyczna; jako takie, w standardowej aplikacji internetowej.ajax byłby drogą do wykonania, IMO - w ten sposób nie ma potrzeby ponownego wyświetlania formularza na błędach, użytkownik nigdy nie idzie nigdzie, po prostu radzisz sobie ze stanem błędu i wyświetlasz go, lub zwracasz sukces i odpowiednio postępujesz. – virtualeyes