Implementer din egen SecurityController
Jeg skrev for nylig en artikel til min virksomhed om administration af brugere og deres autentificering ved hjælp af Symfony2 Core, og derfor uden FOSUserBundle. Efter denne allerede rige første artikel, ønskede jeg at beskrive en anden lige så nyttig del, som vil give os mulighed for hurtigt at konfigurere de væsentlige funktioner, nemlig nulstilling af din adgangskode, ændring af din adgangskode, validering af din konto eller endda tilmelding. Handlinger lige så vigtige, når du har et system, der administrerer brugere.
Konfigurer en SecurityController
For det første, hvis du ikke har fulgt den første tutorial om, hvordan du opsætter brugeradministration, råder jeg dig til at tage et kig. Hvis du fulgte løsningen, skulle du logisk nok have en SecurityController eller noget andet. I mit tilfælde har jeg kun tre metoder, hvoraf kun den ene er rigtig brugbar.
- loginAction
Denne metode forbinder en bruger. - checkAction
Denne metode giver dig simpelthen mulighed for at erklære en rute for firewallen, så en bruger kan oprette forbindelse på serversiden. - logoutAktion
Denne metode bruges til at erklære en rute for firewallen, så en bruger kan afbrydes.
Åbn vores platform for nye brugere
Det ville være særligt interessant, hvis vores brugere kunne tilslutte sig, og derfor kunne registrere sig på forhånd.
Først genererer vi formularen med de oplysninger, du vil spørge din bruger om.
Med hensyn til den formular, du vil bruge til at registrere din bruger, ved, at feltet " adgangskode bør ikke være i din form. Du skal dog tilføje to felter " ikke kortlagt for at få indtastet den ønskede adgangskode to gange.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/ **
* @Metode({"FÅ"})
* @Vej("/register", navn="register")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion register()
{
$form = $ dette->opretForm(ny UserType(UserType::REGISTER), ny Bruger());
afkast matrix(
"form" => $form->createView(),
);
}
|
Så er det, når din bruger kommer tilbage med sin formular udfyldt, at vi bliver nødt til at registrere ham eller afvise 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
|
/ **
* @Metode({"STOLPE"})
* @Vej("/Tilmeld")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion Registrer nu(Anmod $request)
{
$params = $request->request->all()["navn_på_min_form"];
$form = $ dette->opretForm(ny UserType(UserType::REGISTER), ny Bruger());
$form->submit($request);
if (matrixnøgle_eksisterer("plain_password", $params) && array_key_exists("almindelig_adgangskode2", $params) && $params["plain_password"] == $params["almindelig_adgangskode2"]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ dette->container->hent("security.encoder_factory")->getEncoder($data)->encodePassword($params["plain_password"], $data->getSalt()));
$em->persist($data);
$em->flush();
afkast $ dette->omdirigere($ dette->genererUrl("Log på", matrix("besked" => "Du har modtaget en e-mail for at validere din konto. »)));
}
}
afkast matrix(
"fejl" => $params["plain_password"] == $params["almindelig_adgangskode2"]? $form->getErrors(): matrix("De to adgangskoder skal være ens"),
"form" => $form->createView(),
);
}
|
Her vil vi hurtigt detaljere workflow for at registrere en ny bruger.
- Vi ser hvis alle de påkrævede felter er indtastet korrekt, inklusive de to "adgangskode"-felter, og hvis de to sidstnævnte er identiske.
- Vi koder adgangskoden og vi "sætter" det i entiteten.
- I tilfælde af fejl returnerer vi formularen med den fejl, som vi mener bør være detaljeret.
Opret en funktion for at nulstille din adgangskode
Nu kan din bruger logge ind, men hvad gør vi, hvis han mister sin adgangskode. Det er indlysende, at vi ikke vil oprette en kontakt-e-mailadresse dedikeret til dens ubrugelige operationer.
Som du har set ovenfor, erklærer jeg normalt to metoder for hver af mine funktionaliteter: en af mine metoder er ansvarlig for at administrere den visning, der oprettes efter en anmodning GET og et resultat af en anmodning POST. Du kan absolut sammenkæde disse to metoder til en og samme metode.
1
2
3
4
5
6
7
8
9
|
/ **
* @Metode({"FÅ"})
* @Vej("/reset", navn = "nulstil")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion nulstille() {
afkast matrix();
}
|
I et andet trin vil vi erklære den komplementære metode til at administrere anmodningerne 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
|
/ **
* @Metode({"STOLPE"})
* @Vej("/Nulstil")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
offentlige funktion nulstil nu(Anmod $request)
{
$params = $request->request->all();
if (!array_key_exists("Log på", $params)) {
kaste ny undtagelse("Intet login givet");
}
$login = &$params["Log på"];
$em = $ dette->container->hent("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(matrix("Log på" => $login));
if ($bruger == null) {
afkast $ dette->omdirigere($ dette->genererUrl("Log på", matrix()));
}
$adgangskode = "myRandowPassword";
$user->setPassword($ dette->container->hent("security.encoder_factory")->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($bruger);
$em->flush();
// Vi sender adgangskoden via e-mail
afkast $ dette->omdirigere($ dette->genererUrl("Log på", matrix()));
}
|
Denne metode er designet til Nulstil adgangskoden for en bruger, der har givet sit login/brugernavn. I mit tilfælde blev adgangskoden så sendt via e-mail. Jeg vil lade dig tilføje den galante linje.
- Så vi går søge bruger.
- Vi genererer en adgangskode at vi kommer for at informere i brugeren, når han har kodet efter de regler, som du har defineret.
Konfigurer ændring af adgangskode
På dette tidspunkt kan vores bruger generere en ny adgangskode, hvis den blev tabt, men hvis han bare vil ændre den, har vi brug for en gate til at definere en gate.
1
2
3
4
5
6
7
8
9
|
/ **
* @Metode({"FÅ"})
* @Vej("/change", name="change-password")
* @Sikker(roller=”IS_AUTHENTICATED_FULLLY”)
* @Skabelon()
*/
offentlige funktion lave om() {
afkast matrix();
}
|
Her er koden til at generere visningen. Først skal du indtaste din gamle adgangskode, og derefter indtaste din nye adgangskode to gange. Anden gang er det konfirmation.
Nu vil vi se koden til nulstiller adgangskoden. DET behandle svarer til at generere en ny tilfældig adgangskode.
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
|
/ **
* @Metode({"STOLPE"})
* @Vej("/lave om")
* @Sikker(roller=”IS_AUTHENTICATED_FULLLY”)
* @Skabelon()
*/
offentlige funktion skift nu(Anmod $request)
{
$params = $request->request->all();
if (!array_key_exists("nuværende", $params)
|| !array_key_exists("ny", $params)
|| !array_key_exists("ny2", $params))
{
afkast matrix("fejl" => "Udfyld venligst alle felter");
}
$em = $ dette->container->hent("doctrine.orm.default_entity_manager");
$bruger= $ dette->getUser();
$user_encoders = $ dette->container->hent("security.encoder_factory")->getEncoder($bruger);
$user_repository = $em->getRepository("NamespaceMyBundle:User");
$current_password_encoded = $user_encoders->encodePassword($params["nuværende"], $user->getSalt());
$new_password_encoded = $user_encoders->encodePassword($params["ny"], $user->getSalt());
if ($user_repository->findOneBy(matrix("adgangskode" => $current_password_encoded)) == null) {
afkast matrix("fejl" => "Den aktuelle adgangskode er forkert");
} elseif ($params["ny"] != $params["ny2"]) {
afkast matrix("fejl" => "Adgangskoden til de to felter er ikke den samme");
}
$user->setPassword($new_password_encoded);
$em->persist($bruger);
$em->flush();
afkast $ dette->omdirigere($ dette->genererUrl("Log ud", matrix()));
}
|
Hvis du bruger 1 minut på at læse koden, vil du se, at denne er særlig enkel.
- Først tjekker vi, om de tre felter (gammel adgangskode, ny adgangskode og bekræftelse) er indtastet korrekt.
- On indtast adgangskoden nuværende og vi sammenligner det med den nuværende adgangskodei databasen for at se, om det svarer til det gamle indtastede kodeord.
- Vi tjekker om de "to" nye adgangskoder er identisk.
- Indtast den nye adgangskode og skub i enheden.
Aktivering af hans konto
Denne funktion er ikke detaljeret perfekt i andre snippets over. Dens formål er at fjerne blokeringen af en bruger, der lige har registreret sig, når han f.eks. har valideret sin e-mail. Denne funktionalitet er udviklet på næsten alle de platforme, vi kender af flere årsager. For at konfigurere en blokering af en bruger skal du muligvis også implementere en udbyder.
- blok/limit konti falsk og spam.
- verifikator at brugeren har udfyldt en e-mailadresse, der ved første øjekast virker brugbar.
- Fjerne konti, der ikke er blevet valideret efter en vis periode.
Workflow
- En bruger registrerer sig. Hans konto bliver derefter blokeret via et felt specifikt for dig. Dette felt skulle så forhindre ham i at oprette forbindelse, så længe dette felt angiver, at kontoen er deaktiveret.
1
2
3
4
5
6
7
8
|
// NamespaceMyBundleEntityUser
klasse Bruger {
offentlige funktion __konstruere() {
$ dette->token = hash("sha512", uniqid());
}
...
}
|
1
|
$user->setEnabled(falsk);
|
- Brugeren modtog en e-mail, da hans profil var Flush i databasen. Denne e-mail skal være en del af en adresse, som du genererer.
På denne vej, en token eller en unik identifikator skal angives, så den pågældende bruger kan findes. Jeg råder dig til at bruge en UUID4, som er beregnet til at være tilfældig. Du kan finde listen over UUID'er samt beskrivelsen af alle versioner.
1
2
3
4
|
/ **
* @Vej("/aktiver", navn = "aktiver")
*/
offentlige funktion aktivere() {…}
|
1
|
$ dette->genererUrl("aktiver", matrix(« token » => $bruger->hentToken()), sand);
|
Du bør have en URL som denne.
1
|
http://værtsnavn/aktivere?token=mitUnikkeToken
|
- Brugeren åbner sin e-mail og forsøger at aktivere sin konto ved at klikke på det angivne link. Vi går derefter ind i processen nedenfor.
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
|
/ **
* @Metode({"FÅ"})
* @Vej("/aktiver", navn = "aktiver")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion aktivere(Anmod $request) {
$params = matrix();
$token = $request->query->get(« token »);
$em = $ dette->container->hent("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(matrix(« token » => $token));
if ($bruger != null) {
$user->setEnabled(sand);
$em->persist($bruger);
$em->flush();
$params["aktiver"] = sand;
} andet {
$params["aktiver"] = falsk;
}
afkast $params;
}
|
Med denne proces skulle du ikke have noget problem med at aktivere brugerkontovalidering på plads.
Du kan finde denne tilsvarende kode på denne 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
|
brug JMSSecurityExtraBundleAnnotationSikkert;
brug SensioBundleFrameworkExtraBundleKonfigurationMetode;
brug SensioBundleFrameworkExtraBundleKonfigurationR;
brug SensioBundleFrameworkExtraBundleKonfigurationSkabelon;
brug SymfonyBundleFrameworkBundlecontrollercontroller;
brug SymfonyComponentHttpFoundationAnmod om;
brug SymfonyComponentSikkerhedCoreSikkerhedskontekst;
klasse SecurityController udvider controller
{
/ **
* @Metode({"FÅ"})
* @Vej("/login", navn="login")
* @Skabelon()
*/
offentlige funktion Logge på(Anmod $request)
{
$request= $ dette->getRequest();
$session = $request->getSession();
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} andet {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
$params = matrix(
"sidste_brugernavn" => $session->get(SecurityContext::LAST_USERNAME),
"fejl" => $fejl,
"besked" => $request->get("besked"),
);
if ($request->isXmlHttpRequest()) {
afkast $ dette->render("GCDirectoryMainBundle:Security:login-ajax.html.twig", $params);
}
afkast $params;
}
/ **
* @Metode({"STOLPE"})
* @Vej("/login_check", name="login_check")
*/
offentlige funktion kontrollere()
{
kaste ny RuntimeException('Du skal konfigurere kontrolstien til at blive håndteret af firewallen ved hjælp af form_login i din sikkerhedsfirewall-konfiguration.');
}
/ **
* @Metode({"FÅ"})
* @Vej("/logout", navn="logout")
*/
offentlige funktion logout()
{
kaste ny RuntimeException('Du skal aktivere logout i din sikkerhedsfirewall-konfiguration.');
}
/ **
* @Metode({"FÅ"})
* @Vej("/reset", navn = "nulstil")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion nulstille() {
afkast matrix();
}
/ **
* @Metode({"STOLPE"})
* @Vej("/Nulstil")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
offentlige funktion nulstil nu(Anmod $request)
{
$params = $request->request->all();
if (!array_key_exists("Log på", $params)) {
kaste ny undtagelse("Intet login givet");
}
$login = &$params["Log på"];
$em = $ dette->container->hent("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(matrix("Log på" => $login));
if ($bruger == null) {
afkast $ dette->omdirigere($ dette->genererUrl("Log på", matrix()));
}
$adgangskode = "myRandowPassword";
$user->setPassword($ dette->container->hent("security.encoder_factory")->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($bruger);
$em->flush();
afkast $ dette->omdirigere($ dette->genererUrl("Log på", matrix()));
}
/ **
* @Metode({"FÅ"})
* @Vej("/change", name="change-password")
* @Sikker(roller=”IS_AUTHENTICATED_FULLLY”)
* @Skabelon()
*/
offentlige funktion lave om() {
afkast matrix();
}
/ **
* @Metode({"STOLPE"})
* @Vej("/lave om")
* @Sikker(roller=”IS_AUTHENTICATED_FULLLY”)
* @Skabelon()
*/
offentlige funktion skift nu(Anmod $request)
{
$params = $request->request->all();
if (!array_key_exists("nuværende", $params)
|| !array_key_exists("ny", $params)
|| !array_key_exists("ny2", $params))
{
afkast matrix("fejl" => "Udfyld venligst alle felter");
}
$em = $ dette->container->hent("doctrine.orm.default_entity_manager");
$bruger= $ dette->getUser();
$user_encoders = $ dette->container->hent("security.encoder_factory")->getEncoder($bruger);
$user_repository = $em->getRepository("NamespaceMyBundle:User");
$current_password_encoded = $user_encoders->encodePassword($params["nuværende"], $user->getSalt());
$new_password_encoded = $user_encoders->encodePassword($params["ny"], $user->getSalt());
if ($user_repository->findOneBy(matrix("adgangskode" => $current_password_encoded)) == null) {
afkast matrix("fejl" => "Den aktuelle adgangskode er forkert");
} elseif ($params["ny"] != $params["ny2"]) {
afkast matrix("fejl" => "Adgangskoden til de to felter er ikke den samme");
}
$user->setPassword($new_password_encoded);
$em->persist($bruger);
$em->flush();
afkast $ dette->omdirigere($ dette->genererUrl("Log ud", matrix()));
}
/ **
* @Metode({"FÅ"})
* @Vej("/register", navn="register")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion register()
{
$form = $ dette->opretForm(ny UserType(UserType::REGISTER), ny Bruger());
afkast matrix(
"form" => $form->createView(),
);
}
/ **
* @Metode({"STOLPE"})
* @Vej("/Tilmeld")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion Registrer nu(Anmod $request)
{
$params = $request->request->all()["navn_på_min_form"];
$form = $ dette->opretForm(ny UserType(UserType::REGISTER), ny Bruger());
$form->submit($request);
if (matrixnøgle_eksisterer("plain_password", $params) && array_key_exists("almindelig_adgangskode2", $params) && $params["plain_password"] == $params["almindelig_adgangskode2"]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ dette->container->hent("security.encoder_factory")->getEncoder($data)->encodePassword($params["plain_password"], $data->getSalt()));
$em->persist($data);
$em->flush();
afkast $ dette->omdirigere($ dette->genererUrl("Log på", matrix("besked" => "Du har modtaget en e-mail for at validere din konto. »)));
}
}
afkast matrix(
"fejl" => $params["plain_password"] == $params["almindelig_adgangskode2"]? $form->getErrors(): matrix("De to adgangskoder skal være ens"),
"form" => $form->createView(),
);
}
/ **
* @Metode({"FÅ"})
* @Vej("/aktiver", navn = "aktiver")
* @Sikker(roller=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Skabelon()
*/
offentlige funktion aktivere(Anmod $request) {
$params = matrix();
$token = $request->query->get(« token »);
$em = $ dette->container->hent("doctrine.orm.default_entity_manager");
$user = $em->getRepository("NamespaceMyBundle:User")->findOneBy(matrix(« token » => $token));
if ($bruger != null) {
$user->setActive(Bruger::ACTIVE_ACTIVE);
$em->persist($bruger);
$em->flush();
$params["aktiver"] = sand;
} andet {
$params["aktiver"] = falsk;
}
afkast $params;
}
}
|