Zapisuję dane użytkowników w bazie i robię głupie błędy podczas walidacji formularza

Zapis danych użytkowników w MongoDB

O MongoDB pisałam już w dwóch wcześniejszych postach: Jak zacząć z MongoDB? i MongoDB + Spring Data.

Dzisiaj postanowiłam zaimplementować wreszcie zapis danych z formularza użytkownika w mojej nierelacyjnej (dokumentowej) bazie danych.

W poprzednim tekście pokazałam, jakich adnotacji należy użyć w klasie User, żeby jej instancje zostały poprawnie zapisane w bazie danych. Żeby faktycznie zapisać dane z formularza, musiałam tylko dopisać kilka linii w kodzie kontrolera:

Co zrobić z hasłami?

Zależało mi na spełnieniu trzech warunków:

  1. Użytkownik podaje hasło dwa razy, żeby zmniejszyć ryzyko literówki.
  2. Wpisywane hasło jest niewidoczne.
  3. Hasło w bazie danych nie jest przechowywane w postaci jawnej.

Dwa hasła

Dodałam następujące pola do klasy reprezentującej użytkownika:

Specjalnie zaznaczyłam adnotację @Transient. Dzięki jej użyciu wskazane pola (w tym wypadku hasła zapisane jawnym tekstem) nie zostaną zapisane w bazie danych.

Ukrycie literek

Pola musiałam również dopisać do formularza. Użyłam pola input w wersji password, żeby zamiast liter wyświetlić gwiazdki (czy tam kropki).

Funkcja hashująca

Wreszcie, hasła. Nie powinny być przechowywane w bazie danych w postaci jawnej. Powodów jest wiele. Na przykład taki: ludzie często używają tych samych haseł w wielu miejscach. Gdyby administrator bazy danych miał wgląd w hasła do aplikacji, mógłby podjąć próbę zalogowania się na konta użytkowników w innych serwisach (np. gmail) przy użyciu tego samego hasła i adresu email.

Oprócz pokazanych już dwóch pól do wprowadzenia hasła roboczego, klasa User przechowuje jeszcze następujące dwie wartości:

passwordSalt to losowa wartość doklejana do hasła przed jego „zaszyfrowaniem” (dzięki niej w bazie danych nie będzie widać, że dwa użytkownicy przypadkowo użyli tego samego hasła), passwordEncrypted to wynik szyfrowania.

Losowanie i szyfrowanie realizuje następujący pomocniczy serwis, wywoływany z kontrolera dzięki adnotacji @Autowired:

Kontroler wygląda tak:

Błąd 1: strona błędu zamiast komunikatu o błędzie w formularzu

Podanie niepoprawnych danych w formularzu z nieznanego mi powodu zaczęło przenosić mnie na moją własną stronę błędu (zamiast wyświetlenia komunikatu przy polu formularza, które spowodowało problem).

Co się okazało?

W pewnym momencie zmieniłam sygnaturę metody kontrolera z:

na:

ponieważ chciałam dopisać informacje do modelu.

Okazuje się, że parametr reprezentujący BindingResult musi następować bezpośrednio po parametrze, przez który przekazywany jest dotyczący go obiekt (co ma sens, gdy jeden formularz obsługuje wiele obiektów).

Formularz zaczął działać poprawnie po zamianie kolejności parametrów:

Błąd 2: Error during execution of processor ‚org.thymeleaf.spring4.processor.attr.SpringErrorsAttrProcessor’

Kolejny błąd zaskoczył mnie, kiedy testowałam sytuację, w której użytkownik wpisze dwa różne hasła. Okazało się, że poczyniłam złe założenia na temat parametrów metody rejectValue, za pomocą której chciałam przekazać do formularza informację o wykryciu problemu. Napisałam:

zakładając, że drugi parametr to komunikat o błędzie. Tymczasem – to kod błędu. Komunikat można przekazać dopiero w trzecim parametrze (poprawny kod widać na listingu z metodą processPasswords). Błąd wynikał zatem z braku komunikatu o błędzie, który był wymagany w szablonie.

Wreszcie działa

Kod jest dostępny w moim repozytorium GitHub.

Komunikat o niepasujących do siebie hasłach
Komunikat o niepasujących do siebie hasłach
Wyświetlenie informacji o pierwszym lepszym użytkowniku z bazy
Wyświetlenie informacji o pierwszym lepszym użytkowniku z bazy

 

Komentarze

3 myśli nt. „Zapisuję dane użytkowników w bazie i robię głupie błędy podczas walidacji formularza”

  1. Taka drobna sugestia. Nie powinno się używać ani MD5, ani DES, ani ich miksu do zaciemniania haseł w nowych systemach (w starych migracja może być trudna). Znacznie lepszym rozwiązaniem jest bcrypt (jego główną wadą jest fakt że ułatwia przeprowadzenie ataku DoS/DDoS).

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *