Zaimplementuj swój własny SecurityController
Agencja internetowa » Wiadomości cyfrowe » Zaimplementuj swój własny SecurityController

Zaimplementuj swój własny SecurityController

Niedawno napisałem artykuł dla mojej firmy na temat zarządzania użytkownikami i ich uwierzytelniania za pomocą Symfony2 Core natywnie, a więc bez FOSUserBundle. Po tym już bogatym pierwszym artykule chciałem opisać równie przydatną drugą część, która pozwoli nam szybko skonfigurować podstawowe funkcje, a mianowicie resetowanie hasła, zmianę hasła, weryfikację konta, a nawet rejestrację. Akcje równie ważne, gdy masz system zarządzający użytkownikami.

Skonfiguruj SecurityController

Po pierwsze, jeśli nie postępowałeś zgodnie z pierwszym samouczkiem dotyczącym konfigurowania zarządzania użytkownikami, radzę rzucić okiem. Jeśli zastosowałeś rozwiązanie, logicznie powinieneś mieć SecurityController lub coś innego. W moim przypadku mam tylko trzy metody, z których tylko jedna jest naprawdę użyteczna.

  1. logowanieAkcja
    Ta metoda łączy użytkownika.
  2. sprawdźAkcja
    Ta metoda pozwala po prostu zadeklarować trasę dla zapory, umożliwiając użytkownikowi połączenie po stronie serwera.
  3. wylogujAkcja
    Ta metoda jest używana do zadeklarowania trasy dla zapory, która umożliwia rozłączenie użytkownika.

Otwórz naszą platformę dla nowych użytkowników

Byłoby szczególnie interesujące, gdyby nasi użytkownicy mogli się połączyć, a tym samym móc zarejestrować się wcześniej.

Najpierw generujemy formularz z informacjami, o które chcesz zapytać użytkownika.

Jeśli chodzi o formularz, którego użyjesz do rejestracji użytkownika, wiedz, że pole " password nie powinno być w twojej formie. Będziesz jednak musiał dodać dwa pola " nie zmapowane w celu dwukrotnego wprowadzenia żądanego hasła.

1
2
3
4
5
6
7
8
9
10
11
12
13
/ **
 * @Metoda({"DOSTAWAĆ"})
 * @Droga(„/rejestr”, nazwa = „rejestr”)
 * @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
 * @Szablon()
 */
publiczny funkcjonować zarejestrować()
{
    $formularz = $ to->utwórzformularz(nowa Typ użytkownika(Typ użytkownika::REJESTRACJA), nowa Użytkownik());
    powrót szyk(
        "formularz" => $form->createView(),
        );
}

Następnie, gdy twój użytkownik wróci z wypełnionym formularzem, będziemy musieli go zarejestrować lub odrzucić jego plik : p

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/ **
* @Metoda({"POST"})
* @Droga("/rejestr")
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Szablon()
*/
publiczny funkcjonować Zarejestruj się teraz(Poproś $prośba)
{
$params = $żądanie->żądanie->wszystko()[„nazwa_mojego_formularza”];
$formularz = $ to->utwórzformularz(nowa Typ użytkownika(Typ użytkownika::REJESTRACJA), nowa Użytkownik());
$form->prześlij($żądanie);
if (tablica_klucz_istnieje(„zwykłe_hasło”, $params) && array_key_exists(„zwykłe_hasło2”, $params) && $params[„zwykłe_hasło”] == $parametry[„zwykłe_hasło2”]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ to->kontener->pobierz(„fabryka_kodera bezpieczeństwa”)->getEncoder($data)->encodePassword($params[„zwykłe_hasło”], $data->getSalt()));
$em->persist($dane);
$em->flush();
powrót $ to->przekieruj($ to->generujUrl("Zaloguj sie", szyk(" wiadomość " => „Otrzymałeś wiadomość e-mail w celu zweryfikowania konta. »)));
}
}
powrót szyk(
„błędy” => $parametry[„zwykłe_hasło”] == $parametry[„zwykłe_hasło2”]? $form->getErrors(): szyk(„Dwa hasła muszą być takie same”),
"formularz" => $form->createView(),
);
}

Tutaj szybko szczegółowo omówimy workflow aby zarejestrować nowego użytkownika.

  1. Patrzymy czy wszystkie wymagane pola zostały wypełnione poprawnie, w tym dwa pola „hasło” i jeśli te dwa ostatnie są identyczne.
  2. Kodujemy hasło i „ustawiamy” to w encji.
  3. W przypadku jakiegokolwiek błędu zwracamy formularz z błędem, który naszym zdaniem powinien być wyszczególniony.

Utwórz funkcję resetowania hasła

Teraz twój użytkownik może się zalogować, ale co zrobimy, jeśli zgubi hasło. Oczywiste jest, że nie będziemy zakładać kontaktowego adresu e-mail przeznaczonego do jego bezużytecznych operacji.

Jak widać powyżej, zwykle deklaruję dwie metody dla każdej z moich funkcji: jedna z moich metod jest odpowiedzialna za zarządzanie widokiem utworzonym na żądanie GET i wynikiem prośby POST. Możesz absolutnie połączyć te dwie metody w jedną i tę samą metodę.

1
2
3
4
5
6
7
8
9
/ **
  * @Metoda({"DOSTAWAĆ"})
  * @Droga(„/reset”, nazwa=”reset”)
  * @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
  * @Szablon()
  */
  publiczny funkcjonować zresetuj() {
   powrót szyk();
  }

W drugim kroku zadeklarujemy komplementarną metodę zarządzania żądaniami POST.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/ **
* @Metoda({"POST"})
* @Droga("/Resetowanie")
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
publiczny funkcjonować zresetuj teraz(Poproś $prośba)
{
$params = $request->request->all();
if (!array_key_exists(!"Zaloguj sie", $parametry)) {
rzucać nowa Wyjątek(„Nie podano loginu”);
}
$login = &$parametry["Zaloguj sie"];
$em = $ to->kontener->pobierz(„doctrine.orm.default_entity_manager”);
$user = $em->getRepository(„Przestrzeń nazwMyBundle:Użytkownik”)->znajdźOneBy(szyk("Zaloguj sie" => $login));
if ($użytkownik == zero) {
powrót $ to->przekieruj($ to->generujUrl("Zaloguj sie", szyk()));
}
$hasło = „mojeRandowPassword”;
$użytkownik->ustaw hasło($ to->kontener->pobierz(„fabryka_kodera bezpieczeństwa”)->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($użytkownik);
$em->flush();
// Hasło wysyłamy e-mailem
powrót $ to->przekieruj($ to->generujUrl("Zaloguj sie", szyk()));
}

Metoda ta została zaprojektowana do Resetowanie hasło użytkownika, który je podał Login nazwa użytkownika. W moim przypadku hasło zostało następnie wysłane e-mailem. Pozwolę ci dodać tę dzielną kwestię.

  1. Więc jedziemy wyszukaj użytkownika.
  2. Generujemy hasło że przychodzimy poinformować użytkownika, gdy zakoduje zgodnie z regułami, które zdefiniowałeś.

Skonfiguruj zmianę hasła

W tym momencie nasz użytkownik może wygenerować nowe hasło, jeśli zostało utracone, ale w przypadku, gdy chce je tylko zmienić, potrzebujemy bramki, aby zdefiniować bramę.

1
2
3
4
5
6
7
8
9
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/zmień”, nazwa=”zmień-hasło”)
* @Bezpieczne(role=”IS_AUTHENTICATED_FULLY”)
* @Szablon()
*/
publiczny funkcjonować zmiana() {
powrót szyk();
}

Oto kod do generowania widoku. Najpierw musisz wprowadzić swoje stare hasło, a następnie dwukrotnie wprowadzić nowe hasło. Za drugim razem potwierdzenie.

Teraz zobaczymy kod do reseter hasło. TO wygląda tak przypomina generowanie nowego losowego hasła.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/ **
 * @Metoda({"POST"})
 * @Droga("/zmiana")
 * @Bezpieczne(role=”IS_AUTHENTICATED_FULLY”)
 * @Szablon()
 */
publiczny funkcjonować Zmień teraz(Poproś $prośba)
{
    $params = $request->request->all();
    if (!array_key_exists(!"aktualny", $parametry)
        || !array_key_exists("nowy", $parametry)
        || !array_key_exists(„nowy2”, $paramy))
    {
        powrót szyk("błąd" => „Proszę wypełnić wszystkie pola”);
    }
    $em = $ to->kontener->pobierz(„doctrine.orm.default_entity_manager”);
    $użytkownik= $ to->pobierzUżytkownik();
    $user_encoders = $ to->kontener->pobierz(„fabryka_kodera bezpieczeństwa”)->getEncoder($użytkownik);
    $user_repository = $em->getRepository(„Przestrzeń nazwMyBundle:Użytkownik”);
    $current_password_encoded = $user_encoders->encodePassword($params["aktualny"], $user->getSalt());
    $new_password_encoded = $user_encoders->encodePassword($params["nowy"], $user->getSalt());
    if ($ user_repository->findOneBy(szyk("hasło" => $current_password_encoded)) == zero) {
        powrót szyk("błąd" => „Aktualne hasło jest nieprawidłowe”);
    } elseif ($parametry["nowy"] != $parametry[„nowy2”]) {
        powrót szyk("błąd" => „Hasło dwóch pól nie jest takie samo”);
    }
    $user->setPassword($new_password_encoded);
    $em->persist($użytkownik);
    $em->flush();
    powrót $ to->przekieruj($ to->generujUrl("Wyloguj", szyk()));
}

Jeśli poświęcisz 1 minutę na przeczytanie kodu, zobaczysz, że ten jest szczególnie prosty.

  1. Najpierw sprawdzamy, czy trzy pola (stare hasło, nowe hasło i potwierdzenie) zostały wpisane poprawnie.
  2. On Podaj hasło aktualny i porównujemy je z aktualnym hasłemw bazie danych, aby sprawdzić, czy jest zgodne z wprowadzonym starym hasłem.
  3. Sprawdzamy, czy „dwa” nowe hasła są identyczny.
  4. Wprowadź nowe hasło i naciskać w jednostce.

Aktywacja jego konta

Ta funkcja nie jest szczegółowo szczegółowo w innych Fragmenty powyżej. Jego celem jest odblokowanie użytkownika, który właśnie się zarejestrował, gdy np. zweryfikował swój adres e-mail. Ta funkcjonalność jest rozwijana na prawie wszystkich znanych nam platformach z kilku powodów. Aby skonfigurować blokowanie użytkownika, może być również konieczne wdrożenie dostawcy.

  • blok/ limit kont imitacja i spam.
  • Weryfikator że użytkownik podał adres e-mail, który na pierwszy rzut oka wydaje się użyteczny.
  • Usunąć konta, które nie zostały zweryfikowane po pewnym czasie.

Workflow

  1. Użytkownik rejestruje się. Jego konto jest następnie blokowane za pomocą odpowiedniego pola. To pole powinno wtedy uniemożliwić mu połączenie, o ile to pole wskazuje, że konto jest wyłączone.
1
2
3
4
5
6
7
8
// Przestrzeń nazwMyBundleEntityUser
klasa Użytkownik {
publiczny funkcjonować __zbudować() {
$ to->token = skrót („sha512”, uniqid());
}
...
}
1
$user->setEnabled(fałszywy);
  1. Użytkownik otrzymał wiadomość e-mail, gdy jego profil był spłukać w bazie danych. Ten e-mail musi być częścią adresu, który generujesz.
    Na tej drodze A token lub niepowtarzalny identyfikator umożliwiający odnalezienie danego użytkownika. Radzę używać UUID4, który ma być losowy. Możesz znaleźć listę identyfikatorów UUID, a także opis wszystkich wersji.
1
2
3
4
/ **
* @Droga(„/aktywuj”, nazwa = „aktywuj”)
*/
publiczny funkcjonować aktywowany() {…}
1
$ to->generujUrl("Aktywuj", szyk(« token » => $użytkownik->pobierzToken()), prawdziwy);

Powinieneś mieć taki adres URL.

1
http://nazwa hosta/aktywować?token=mójUnikatowyToken
  1. Użytkownik otwiera swój e-mail i próbuje aktywować swoje konto, klikając podany link. Następnie przechodzimy do poniższego procesu.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/ **
 * @Metoda({"DOSTAWAĆ"})
 * @Droga(„/aktywuj”, nazwa = „aktywuj”)
 * @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
 * @Szablon()
 */
publiczny funkcjonować aktywowany(Poproś $prośba) {
    $parametry = szyk();
    $token = $żądanie->zapytanie->pobierz(« token »);
    $em = $ to->kontener->pobierz(„doctrine.orm.default_entity_manager”);
$user = $em->getRepository(„Przestrzeń nazwMyBundle:Użytkownik”)->znajdźOneBy(szyk(« token » => $token));
    if ($użytkownik != zero) {
        $user->setEnabled(prawdziwy);
        $em->persist($użytkownik);
        $em->flush();
        $parametry["Aktywuj"] = prawdziwy;
    } więcej {
        $parametry["Aktywuj"] = fałszywy;
    }
    powrót $paramy;
}

Dzięki temu procesowi nie powinieneś mieć problemu z włączeniem weryfikacji konta użytkownika.

Możesz znaleźć ten równoważny kod w tym Gist.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
posługiwać się JMSBezpieczeństwoDodatkowy pakietAdnotacjaZabezpieczać;
posługiwać się SensioZapakowaćFrameworkExtraBundlesystemuMetoda wykonania;
posługiwać się SensioZapakowaćFrameworkExtraBundlesystemuTrasa;
posługiwać się SensioZapakowaćFrameworkExtraBundlesystemuszablon;
posługiwać się SymfonyZapakowaćPakiet ramowykontrolerkontroler;
posługiwać się SymfonySkładnikHttp FoundationPROŚBA;
posługiwać się SymfonySkładnikBezpieczeństwordzeńKontekst bezpieczeństwa;
klasa Kontroler bezpieczeństwa rozciąga się kontroler
{
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/login”, nazwa=”login”)
* @Szablon()
*/
publiczny funkcjonować Zaloguj Się(Poproś $prośba)
{
$prośba = $ to->pobierzŻądanie();
$session = $request->getSession();
if ($request->atrybuty->has(SecurityContext::AUTHENTICATION_ERROR)) {
$błąd = $żądanie->atrybuty->get(SecurityContext::AUTHENTICATION_ERROR);
} więcej {
$błąd = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
$parametry = szyk(
„ostatnia_nazwa użytkownika” => $session->get(SecurityContext::LAST_USERNAME),
"błąd" => $błąd,
" wiadomość " => $żądanie->pobierz(" wiadomość "),
);
if ($request->isXmlHttpRequest()) {
powrót $ to->renderuj(„GCDirectoryMainBundle:Security:login-ajax.html.twig”, $parametry);
}
powrót $paramy;
}
/ **
* @Metoda({"POST"})
* @Droga(„/login_check”, nazwa=”login_check”)
*/
publiczny funkcjonować ZOBACZ()
{
rzucać nowa RuntimeException ('Musisz skonfigurować ścieżkę sprawdzania, która ma być obsługiwana przez zaporę, używając form_login w konfiguracji zapory bezpieczeństwa.');
}
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/ wyloguj”, nazwa = „wyloguj”)
*/
publiczny funkcjonować wyloguj się()
{
rzucać nowa RuntimeException („Musisz aktywować wylogowanie w konfiguracji zapory bezpieczeństwa”.);
}
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/reset”, nazwa=”reset”)
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Szablon()
*/
publiczny funkcjonować zresetuj() {
powrót szyk();
}
/ **
* @Metoda({"POST"})
* @Droga("/Resetowanie")
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
publiczny funkcjonować zresetuj teraz(Poproś $prośba)
{
$params = $request->request->all();
if (!array_key_exists(!"Zaloguj sie", $parametry)) {
rzucać nowa Wyjątek(„Nie podano loginu”);
}
$login = &$parametry["Zaloguj sie"];
$em = $ to->kontener->pobierz(„doctrine.orm.default_entity_manager”);
$user = $em->getRepository(„Przestrzeń nazwMyBundle:Użytkownik”)->znajdźOneBy(szyk("Zaloguj sie" => $login));
if ($użytkownik == zero) {
powrót $ to->przekieruj($ to->generujUrl("Zaloguj sie", szyk()));
}
$hasło = „mojeRandowPassword”;
$użytkownik->ustaw hasło($ to->kontener->pobierz(„fabryka_kodera bezpieczeństwa”)->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($użytkownik);
$em->flush();
powrót $ to->przekieruj($ to->generujUrl("Zaloguj sie", szyk()));
}
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/zmień”, nazwa=”zmień-hasło”)
* @Bezpieczne(role=”IS_AUTHENTICATED_FULLY”)
* @Szablon()
*/
publiczny funkcjonować zmiana() {
powrót szyk();
}
/ **
* @Metoda({"POST"})
* @Droga("/zmiana")
* @Bezpieczne(role=”IS_AUTHENTICATED_FULLY”)
* @Szablon()
*/
publiczny funkcjonować Zmień teraz(Poproś $prośba)
{
$params = $request->request->all();
if (!array_key_exists(!"aktualny", $parametry)
|| !array_key_exists("nowy", $parametry)
|| !array_key_exists(„nowy2”, $paramy))
{
powrót szyk("błąd" => „Proszę wypełnić wszystkie pola”);
}
$em = $ to->kontener->pobierz(„doctrine.orm.default_entity_manager”);
$użytkownik= $ to->pobierzUżytkownik();
$user_encoders = $ to->kontener->pobierz(„fabryka_kodera bezpieczeństwa”)->getEncoder($użytkownik);
$user_repository = $em->getRepository(„Przestrzeń nazwMyBundle:Użytkownik”);
$current_password_encoded = $user_encoders->encodePassword($params["aktualny"], $user->getSalt());
$new_password_encoded = $user_encoders->encodePassword($params["nowy"], $user->getSalt());
if ($ user_repository->findOneBy(szyk("hasło" => $current_password_encoded)) == zero) {
powrót szyk("błąd" => „Aktualne hasło jest nieprawidłowe”);
} elseif ($parametry["nowy"] != $parametry[„nowy2”]) {
powrót szyk("błąd" => „Hasło dwóch pól nie jest takie samo”);
}
$user->setPassword($new_password_encoded);
$em->persist($użytkownik);
$em->flush();
powrót $ to->przekieruj($ to->generujUrl("Wyloguj", szyk()));
}
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/rejestr”, nazwa = „rejestr”)
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Szablon()
*/
publiczny funkcjonować zarejestrować()
{
$formularz = $ to->utwórzformularz(nowa Typ użytkownika(Typ użytkownika::REJESTRACJA), nowa Użytkownik());
powrót szyk(
"formularz" => $form->createView(),
);
}
/ **
* @Metoda({"POST"})
* @Droga("/rejestr")
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Szablon()
*/
publiczny funkcjonować Zarejestruj się teraz(Poproś $prośba)
{
$params = $żądanie->żądanie->wszystko()[„nazwa_mojego_formularza”];
$formularz = $ to->utwórzformularz(nowa Typ użytkownika(Typ użytkownika::REJESTRACJA), nowa Użytkownik());
$form->prześlij($żądanie);
if (tablica_klucz_istnieje(„zwykłe_hasło”, $params) && array_key_exists(„zwykłe_hasło2”, $params) && $params[„zwykłe_hasło”] == $parametry[„zwykłe_hasło2”]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ to->kontener->pobierz(„fabryka_kodera bezpieczeństwa”)->getEncoder($data)->encodePassword($params[„zwykłe_hasło”], $data->getSalt()));
$em->persist($dane);
$em->flush();
powrót $ to->przekieruj($ to->generujUrl("Zaloguj sie", szyk(" wiadomość " => „Otrzymałeś wiadomość e-mail w celu zweryfikowania konta. »)));
}
}
powrót szyk(
„błędy” => $parametry[„zwykłe_hasło”] == $parametry[„zwykłe_hasło2”]? $form->getErrors(): szyk(„Dwa hasła muszą być takie same”),
"formularz" => $form->createView(),
);
}
/ **
* @Metoda({"DOSTAWAĆ"})
* @Droga(„/aktywuj”, nazwa = „aktywuj”)
* @Bezpieczne(role=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Szablon()
*/
publiczny funkcjonować aktywowany(Poproś $prośba) {
$parametry = szyk();
$token = $żądanie->zapytanie->pobierz(« token »);
$em = $ to->kontener->pobierz(„doctrine.orm.default_entity_manager”);
$user = $em->getRepository(„Przestrzeń nazwMyBundle:Użytkownik”)->znajdźOneBy(szyk(« token » => $token));
if ($użytkownik != zero) {
$user->setActive(Użytkownik::ACTIVE_ACTIVE);
$em->persist($użytkownik);
$em->flush();
$parametry["Aktywuj"] = prawdziwy;
} więcej {
$parametry["Aktywuj"] = fałszywy;
}
powrót $paramy;
}
}

★ ★ ★ ★ ★