Implementera din egen SecurityController
Webbyrå » Digitala nyheter » Implementera din egen SecurityController

Implementera din egen SecurityController

Jag skrev nyligen en artikel för mitt företag om att hantera användare och deras autentisering inbyggt med Symfony2 Core, och därför utan FOSUserBundle. Efter denna redan rika första artikel ville jag beskriva en andra lika användbar del som gör att vi snabbt kan ställa in de väsentliga funktionerna, nämligen att återställa ditt lösenord, ändra ditt lösenord, validera ditt konto eller till och med registrera dig. Åtgärder lika viktiga när du har ett system som hanterar användare.

Konfigurera en SecurityController

Först, om du inte har följt den första handledningen om hur du ställer in användarhantering, råder jag dig att ta en titt. Om du följde lösningen borde du logiskt sett ha en SecurityController eller något annat. I mitt fall har jag bara tre metoder, varav bara en är riktigt användbar.

  1. loginAction
    Denna metod kopplar en användare.
  2. checkAction
    Denna metod låter dig helt enkelt deklarera en rutt för brandväggen, vilket gör att en användare kan ansluta på serversidan.
  3. logga utAktion
    Denna metod används för att deklarera en rutt för brandväggen så att en användare kan kopplas bort.

Öppna vår plattform för nya användare

Det skulle vara särskilt intressant om våra användare kunde ansluta och därför kunna registrera sig i förväg.

Först genererar vi formuläret med den information du vill fråga din användare.

Angående formuläret du kommer att använda för att registrera din användare, vet att fältet " Lösenord bör inte vara i din form. Du måste dock lägga till två fält " inte kartlagt för att få önskat lösenord inmatat två gånger.

1
2
3
4
5
6
7
8
9
10
11
12
13
/ **
 * @Metod({"SKAFFA SIG"})
 * @Väg("/register", name="register")
 * @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
 * @Mall()
 */
allmän fungera registrera()
{
    $form = $ detta->skapaForm(ny UserType(UserType::REGISTER), ny Användare());
    avkastning array(
        "form" => $form->createView(),
        );
}

Sedan är det när din användare kommer tillbaka med sitt formulär ifyllt som vi måste registrera honom eller avvisa hans fil :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
/ **
* @Metod({"POSTA"})
* @Väg("/Registrera")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Mall()
*/
allmän fungera registrera nu(Begär $request)
{
$params = $request->request->all()["namn_på_min_form"];
$form = $ detta->skapaForm(ny UserType(UserType::REGISTER), ny Användare());
$form->submit($request);
if (array_key_exists("vanligt_lösenord", $params) && array_key_exists("vanligt_lösenord2", $params) && $params["vanligt_lösenord"] == $params["vanligt_lösenord2"]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ detta->behållare->få("security.encoder_factory")->getEncoder($data)->encodePassword($params["vanligt_lösenord"], $data->getSalt()));
$em->persist($data);
$em->flush();
avkastning $ detta->redirect($ detta->generateUrl("logga in", array("meddelande" => "Du har fått ett e-postmeddelande för att validera ditt konto. »)));
}
}
avkastning array(
"fel" => $params["vanligt_lösenord"] == $params["vanligt_lösenord2"]? $form->getErrors(): array("De två lösenorden måste vara samma"),
"form" => $form->createView(),
);
}

Här kommer vi snabbt att detaljera arbetsflöde för att registrera en ny användare.

  1. Vi kollar om alla obligatoriska fält har angetts korrekt, inklusive de två "lösenordsfälten", och om de två senare är identiska.
  2. Vi kodar lösenordet och vi "ställer in" det i entiteten.
  3. Vid eventuella fel returnerar vi formuläret med det fel som vi anser bör vara detaljerat.

Skapa en funktion för att återställa ditt lösenord

Nu kan din användare logga in men vad gör vi om han tappar bort sitt lösenord. Det är uppenbart att vi inte kommer att skapa en e-postadress för kontakt som är dedikerad till dess värdelösa verksamhet.

Som du har sett ovan, deklarerar jag vanligtvis två metoder för var och en av mina funktioner: en av mina metoder är ansvarig för att hantera vyn som skapas efter en förfrågan och ett resultat av en begäran POST. Du kan absolut sammanfoga dessa två metoder till en och samma metod.

1
2
3
4
5
6
7
8
9
/ **
  * @Metod({"SKAFFA SIG"})
  * @Väg("/reset", name="reset")
  * @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
  * @Mall()
  */
  allmän fungera återställa() {
   avkastning array();
  }

I ett andra steg kommer vi att deklarera den kompletterande metoden som hanterar förfrågningarna 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
/ **
* @Metod({"POSTA"})
* @Väg("/återställa")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
allmän fungera återställ nu(Begär $request)
{
$params = $request->request->all();
if (!array_key_exists("logga in", $params)) {
kasta ny undantag("Ingen inloggning ges");
}
$login = &$params["logga in"];
$em = $ detta->behållare->få("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(array("logga in" => $login));
if ($användare == null) {
avkastning $ detta->redirect($ detta->generateUrl("logga in", array()));
}
$lösenord = "myRandowPassword";
$user->setPassword($ detta->behållare->få("security.encoder_factory")->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($användare);
$em->flush();
// Vi skickar lösenordet via e-post
avkastning $ detta->redirect($ detta->generateUrl("logga in", array()));
}

Denna metod var utformad för att återställare lösenordet för en användare som angav sitt inloggning/användarnamn. I mitt fall skickades sedan lösenordet via e-post. Jag låter dig lägga till den där galanta raden.

  1. Så vi går sökanvändare.
  2. Vi skapar ett lösenord att vi kommer att informera i användaren när denne har kodat enligt de regler som du har definierat.

Ställ in lösenordsändring

Vid det här laget kan vår användare generera ett nytt lösenord om det försvann, men om han bara vill ändra det behöver vi en grind för att definiera en grind.

1
2
3
4
5
6
7
8
9
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/change", name="change-password")
* @Säkra(roller=”IS_AUTHENTICATED_FULLY”)
* @Mall()
*/
allmän fungera byta() {
avkastning array();
}

Här är koden för att generera vyn. Först måste du ange ditt gamla lösenord och sedan ange ditt nya lösenord två gånger. Andra gången är bekräftelse.

Nu kommer vi att se koden till återställare lösenordet. DE process liknar att generera ett nytt slumpmässigt lösenord.

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
/ **
 * @Metod({"POSTA"})
 * @Väg("/förändra")
 * @Säkra(roller=”IS_AUTHENTICATED_FULLY”)
 * @Mall()
 */
allmän fungera ändra nu(Begär $request)
{
    $params = $request->request->all();
    if (!array_key_exists("nuvarande", $params)
        || !array_key_exists("ny", $params)
        || !array_key_exists("ny2", $params))
    {
        avkastning array("fel" => "Snälla Fyll i alla fält");
    }
    $em = $ detta->behållare->få("doctrine.orm.default_entity_manager");
    $användare = $ detta->getUser();
    $user_encoders = $ detta->behållare->få("security.encoder_factory")->getEncoder($användare);
    $user_repository = $em->getRepository("NamespaceMyBundle:User");
    $current_password_encoded = $user_encoders->encodePassword($params["nuvarande"], $user->getSalt());
    $new_password_encoded = $user_encoders->encodePassword($params["ny"], $user->getSalt());
    if ($user_repository->findOneBy(array("Lösenord" => $current_password_encoded)) == null) {
        avkastning array("fel" => "Det aktuella lösenordet är fel");
    } annat ($params["ny"] != $params["ny2"]) {
        avkastning array("fel" => "Lösenordet för två fält är inte detsamma");
    }
    $user->setPassword($new_password_encoded);
    $em->persist($användare);
    $em->flush();
    avkastning $ detta->redirect($ detta->generateUrl("logga ut", array()));
}

Om du tar 1 minut att läsa koden kommer du att se att den här är särskilt enkel.

  1. Först kontrollerar vi om de tre fälten (gammalt lösenord, nytt lösenord och bekräftelse) har angetts korrekt.
  2. On ange lösenordet nuvarande och vi jämför det med det nuvarande lösenordeti databasen för att se om det stämmer överens med det gamla lösenordet.
  3. Vi kontrollerar om de "två" nya lösenorden är det identiska.
  4. Ange det nya lösenordet och tryck i enheten.

Aktivering av hans konto

Denna funktion är inte detaljerad perfekt i andra snippets ovan. Syftet är att avblockera en användare som just har registrerat sig, när han till exempel har validerat sin e-post. Denna funktionalitet är utvecklad på nästan alla plattformar vi känner till av flera anledningar. För att ställa in en blockering av en användare kan du också behöva implementera en leverantör.

  • blocket/limit-konton fejka och skräppost.
  • Kontrollanten att användaren har fyllt i en e-postadress som verkar användbar vid första anblicken.
  • Ta bort konton som inte har validerats efter en viss tid.

Arbetsflöde

  1. En användare registrerar sig. Hans konto blockeras sedan via ett specifikt fält för dig. Detta fält bör då hindra honom från att ansluta så länge som detta fält indikerar att kontot är inaktiverat.
1
2
3
4
5
6
7
8
// NamespaceMyBundleEntityUser
klass Användare {
allmän fungera __konstruera() {
$ detta->token = hash(“sha512”, uniqid());
}
.
}
1
$user->setEnabled(falsk);
  1. Användaren fick ett e-postmeddelande när hans profil var spola i databasen. Detta e-postmeddelande måste vara en del av en adress som du genererar.
    På denna väg, en token eller unik identifierare måste ges så att den berörda användaren kan hittas. Jag råder dig att använda en UUID4 som är avsedd att vara slumpmässig. Du kan hitta listan över UUID samt beskrivningen av alla versioner.
1
2
3
4
/ **
* @Väg("/aktivera", namn = "aktivera")
*/
allmän fungera aktivera() {...}
1
$ detta->generateUrl("Aktivera", array(« token » => $user->getToken()), sann);

Du bör ha en sådan här URL.

1
http://värdnamn/aktivera?token=myUniqueToken
  1. Användaren öppnar sin e-post och försöker aktivera sitt konto genom att klicka på länken. Vi går sedan in i processen nedan.
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
/ **
 * @Metod({"SKAFFA SIG"})
 * @Väg("/aktivera", namn = "aktivera")
 * @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
 * @Mall()
 */
allmän fungera aktivera(Begär $request) {
    $params = array();
    $token = $request->query->get(« token »);
    $em = $ detta->behållare->få("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(array(« token » => $token));
    if ($användare != null) {
        $user->setEnabled(sann);
        $em->persist($användare);
        $em->flush();
        $params["Aktivera"🇧🇷 sann;
    } annars {
        $params["Aktivera"🇧🇷 falsk;
    }
    avkastning $params;
}

Med den här processen bör du inte ha några problem med att aktivera användarkontovalidering på plats.

Du kan hitta denna motsvarande kod på denna 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
användning JMSSecurityExtraBundleanteckningSäkerhet;
användning SensioBuntFrameworkExtraBundlekonfigurationMetod;
användning SensioBuntFrameworkExtraBundlekonfigurationRutt;
användning SensioBuntFrameworkExtraBundlekonfigurationMall;
användning SymfonyBuntFrameworkBundleRegulatorRegulator;
användning SymfonyKomponentHttpFoundationBegäran;
användning SymfonyKomponentsäkerhetKärnaSäkerhetskontext;
klass Säkerhetskontroller sträcker Regulator
{
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/login", namn ="inloggning")
* @Mall()
*/
allmän fungera logga in(Begär $request)
{
$request= $ detta->getRequest();
$session = $request->getSession();
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} annars {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
$params = array(
"last_username" => $session->get(SecurityContext::LAST_USERNAME),
"fel" => $fel,
"meddelande" => $request->get("meddelande"),
);
if ($request->isXmlHttpRequest()) {
avkastning $ detta->render("GCDirectoryMainBundle:Security:login-ajax.html.twig", $params);
}
avkastning $params;
}
/ **
* @Metod({"POSTA"})
* @Väg("/login_check", name="login_check")
*/
allmän fungera ta()
{
kasta ny RuntimeException ('Du måste konfigurera sökvägen för att hanteras av brandväggen med form_login i din säkerhetsbrandväggskonfiguration.');
}
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/logga ut", namn = "logga ut")
*/
allmän fungera logout()
{
kasta ny RuntimeException ("Du måste aktivera utloggningen i din säkerhetsbrandväggskonfiguration.");
}
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/reset", name="reset")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Mall()
*/
allmän fungera återställa() {
avkastning array();
}
/ **
* @Metod({"POSTA"})
* @Väg("/återställa")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
allmän fungera återställ nu(Begär $request)
{
$params = $request->request->all();
if (!array_key_exists("logga in", $params)) {
kasta ny undantag("Ingen inloggning ges");
}
$login = &$params["logga in"];
$em = $ detta->behållare->få("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(array("logga in" => $login));
if ($användare == null) {
avkastning $ detta->redirect($ detta->generateUrl("logga in", array()));
}
$lösenord = "myRandowPassword";
$user->setPassword($ detta->behållare->få("security.encoder_factory")->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($användare);
$em->flush();
avkastning $ detta->redirect($ detta->generateUrl("logga in", array()));
}
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/change", name="change-password")
* @Säkra(roller=”IS_AUTHENTICATED_FULLY”)
* @Mall()
*/
allmän fungera byta() {
avkastning array();
}
/ **
* @Metod({"POSTA"})
* @Väg("/förändra")
* @Säkra(roller=”IS_AUTHENTICATED_FULLY”)
* @Mall()
*/
allmän fungera ändra nu(Begär $request)
{
$params = $request->request->all();
if (!array_key_exists("nuvarande", $params)
|| !array_key_exists("ny", $params)
|| !array_key_exists("ny2", $params))
{
avkastning array("fel" => "Snälla Fyll i alla fält");
}
$em = $ detta->behållare->få("doctrine.orm.default_entity_manager");
$användare = $ detta->getUser();
$user_encoders = $ detta->behållare->få("security.encoder_factory")->getEncoder($användare);
$user_repository = $em->getRepository("NamespaceMyBundle:User");
$current_password_encoded = $user_encoders->encodePassword($params["nuvarande"], $user->getSalt());
$new_password_encoded = $user_encoders->encodePassword($params["ny"], $user->getSalt());
if ($user_repository->findOneBy(array("Lösenord" => $current_password_encoded)) == null) {
avkastning array("fel" => "Det aktuella lösenordet är fel");
} annat ($params["ny"] != $params["ny2"]) {
avkastning array("fel" => "Lösenordet för två fält är inte detsamma");
}
$user->setPassword($new_password_encoded);
$em->persist($användare);
$em->flush();
avkastning $ detta->redirect($ detta->generateUrl("logga ut", array()));
}
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/register", name="register")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Mall()
*/
allmän fungera registrera()
{
$form = $ detta->skapaForm(ny UserType(UserType::REGISTER), ny Användare());
avkastning array(
"form" => $form->createView(),
);
}
/ **
* @Metod({"POSTA"})
* @Väg("/Registrera")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Mall()
*/
allmän fungera registrera nu(Begär $request)
{
$params = $request->request->all()["namn_på_min_form"];
$form = $ detta->skapaForm(ny UserType(UserType::REGISTER), ny Användare());
$form->submit($request);
if (array_key_exists("vanligt_lösenord", $params) && array_key_exists("vanligt_lösenord2", $params) && $params["vanligt_lösenord"] == $params["vanligt_lösenord2"]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ detta->behållare->få("security.encoder_factory")->getEncoder($data)->encodePassword($params["vanligt_lösenord"], $data->getSalt()));
$em->persist($data);
$em->flush();
avkastning $ detta->redirect($ detta->generateUrl("logga in", array("meddelande" => "Du har fått ett e-postmeddelande för att validera ditt konto. »)));
}
}
avkastning array(
"fel" => $params["vanligt_lösenord"] == $params["vanligt_lösenord2"]? $form->getErrors(): array("De två lösenorden måste vara samma"),
"form" => $form->createView(),
);
}
/ **
* @Metod({"SKAFFA SIG"})
* @Väg("/aktivera", namn = "aktivera")
* @Säkra(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Mall()
*/
allmän fungera aktivera(Begär $request) {
$params = array();
$token = $request->query->get(« token »);
$em = $ detta->behållare->få("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(array(« token » => $token));
if ($användare != null) {
$user->setActive(Användare::ACTIVE_ACTIVE);
$em->persist($användare);
$em->flush();
$params["Aktivera"🇧🇷 sann;
} annars {
$params["Aktivera"🇧🇷 falsk;
}
avkastning $params;
}
}

★ ★ ★ ★ ★