Implementeer uw eigen SecurityController
Ik heb onlangs een artikel geschreven voor mijn bedrijf over het beheren van gebruikers en hun authenticatie native met behulp van de Symfony2 Core, en dus zonder FOSUserBundle. Na dit toch al rijke eerste artikel, wilde ik een tweede, even nuttig onderdeel beschrijven waarmee we snel de essentiële functies kunnen instellen, namelijk uw wachtwoord opnieuw instellen, uw wachtwoord wijzigen, uw account valideren of zelfs registreren. Acties die net zo essentieel zijn als u een systeem heeft dat gebruikers beheert.
Stel een SecurityController in
Ten eerste, als je de eerste tutorial over het instellen van gebruikersbeheer niet hebt gevolgd, raad ik je aan om een kijkje te nemen. Als je de oplossing hebt gevolgd, zou je logischerwijs een SecurityController of iets anders moeten hebben. In mijn geval heb ik maar drie methoden, waarvan er maar één echt bruikbaar is.
- loginActie
Deze methode verbindt een gebruiker. - checkActie
Met deze methode kunt u eenvoudigweg een route voor de firewall declareren, zodat een gebruiker verbinding kan maken aan de serverzijde. - uitloggenActie
Deze methode wordt gebruikt om een route voor de firewall aan te geven waardoor een gebruiker kan worden losgekoppeld.
Open ons platform voor nieuwe gebruikers
Het zou bijzonder interessant zijn als onze gebruikers verbinding kunnen maken en zich dus vooraf kunnen registreren.
Eerst genereren we het formulier met de informatie die u aan uw gebruiker wilt vragen.
Wat betreft het formulier dat u gebruikt om uw gebruiker te registreren, weet dat het veld " wachtwoord zou niet in jouw vorm moeten zijn. U moet echter twee velden toevoegen " niet in kaart gebracht om het gewenste wachtwoord twee keer in te voeren.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/register”, name=”registreren”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie registreren()
{
$formulier = $ This->MaakFormulier(nieuwe Gebruikerstype(Gebruikerstype::REGISTREER), nieuwe Gebruiker());
terugkeer reeks(
"formulier" => $form->createView(),
);
}
|
Als uw gebruiker dan terugkomt met zijn ingevulde formulier, moeten we hem registreren of zijn bestand afwijzen :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
|
/ **
* @Methode({"NA"})
* @Weg("/register")
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie Registreer nu(Verzoek $verzoek)
{
$params = $request->request->all()["naam_van_mijn_formulier"];
$formulier = $ This->MaakFormulier(nieuwe Gebruikerstype(Gebruikerstype::REGISTREER), nieuwe Gebruiker());
$formulier->verzenden($verzoek);
if (array_key_exists("plain_wachtwoord", $params) && array_key_exists("plain_password2", $params) && $params["plain_wachtwoord"] == $parameters["plain_password2"]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ This->container->krijgen("beveiliging.encoder_factory")->getEncoder($data)->encodePassword($params["plain_wachtwoord"], $data->getSalt()));
$em->persist($data);
$em->flush();
terugkeer $ This->omleiden($ This->Url genereren("Log in", reeks(" bericht " => “Je hebt een e-mail ontvangen om je account te valideren. »)));
}
}
terugkeer reeks(
"fouten" => $params["plain_wachtwoord"] == $parameters["plain_password2"]? $form->getErrors(): reeks(“De twee wachtwoorden moeten hetzelfde zijn”),
"formulier" => $form->createView(),
);
}
|
Hier zullen we snel ingaan op de workflow om een nieuwe gebruiker te registreren.
- Wij kijken als alle verplichte velden correct zijn ingevuld, inclusief de twee "wachtwoord"-velden, en als de laatste twee identiek zijn.
- We coderen het wachtwoord en we "zetten" het in de entiteit.
- In het geval van een fout, sturen we het formulier terug met de fout waarvan we denken dat deze gedetailleerd moet zijn.
Maak een functie om uw wachtwoord opnieuw in te stellen
Nu kan uw gebruiker inloggen, maar wat doen we als hij zijn wachtwoord verliest? Het is duidelijk dat we geen e-mailadres voor contact gaan instellen dat speciaal is bedoeld voor nutteloze operaties.
Zoals je hierboven hebt gezien, declareer ik meestal twee methoden voor elk van mijn functies: een van mijn methoden is verantwoordelijk voor het beheer van de weergave die is gemaakt naar aanleiding van een verzoek GET en een resultaat van een verzoek POST. U kunt deze twee methoden absoluut samenvoegen tot één en dezelfde methode.
1
2
3
4
5
6
7
8
9
|
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/reset”, naam=”reset”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie opnieuw in te stellen() {
terugkeer reeks();
}
|
In een tweede stap zullen we de aanvullende methode voor het beheer van de verzoeken aangeven 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
|
/ **
* @Methode({"NA"})
* @Weg(“/ resetten”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
publiek functie nu resetten(Verzoek $verzoek)
{
$params = $request->request->all();
if (!array_key_exists("Log in", $parameters)) {
Gooi nieuwe uitzondering(“Geen login gegeven”);
}
$login = &$params["Log in"];
$ em = $ This->container->krijgen(“doctrine.orm.default_entity_manager”);
$gebruiker = $em->getRepository("NaamruimteMyBundle: Gebruiker")->vindOneBy(reeks("Log in" => $login));
if ($gebruiker == nul) {
terugkeer $ This->omleiden($ This->Url genereren("Log in", reeks()));
}
$ wachtwoord = "mijnWillekeurigWachtwoord";
$user->setPassword($ This->container->krijgen("beveiliging.encoder_factory")->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($gebruiker);
$em->flush();
// We sturen het wachtwoord per e-mail
terugkeer $ This->omleiden($ This->Url genereren("Log in", reeks()));
}
|
Deze methode is ontworpen om resetten het wachtwoord van een gebruiker die het zijne heeft opgegeven login gebruikersnaam. In mijn geval werd het wachtwoord vervolgens per e-mail verzonden. Ik laat je die dappere regel toevoegen.
- Dus we gaan zoek gebruiker.
- We genereren een wachtwoord dat we de gebruiker komen informeren zodra hij heeft gecodeerd volgens de regels die u hebt gedefinieerd.
Wachtwoord wijzigen instellen
Op dit moment kan onze gebruiker een nieuw wachtwoord genereren als het verloren is gegaan, maar als hij het gewoon wil wijzigen, hebben we een poort nodig om een poort te definiëren.
1
2
3
4
5
6
7
8
9
|
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/wijzigen”, naam=”wachtwoord wijzigen”)
* @Zeker(rollen=”IS_AUTHENTICATED_FULLY”)
* @Sjabloon()
*/
publiek functie verandering() {
terugkeer reeks();
}
|
Hier is de code om de weergave te genereren. Eerst moet u uw oude wachtwoord invoeren en daarna tweemaal uw nieuwe wachtwoord. De tweede keer is bevestiging.
Nu zullen we de code zien resetter het wachtwoord. DE Dit proces is vergelijkbaar met het genereren van een nieuw willekeurig wachtwoord.
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
|
/ **
* @Methode({"NA"})
* @Weg("/wijziging")
* @Zeker(rollen=”IS_AUTHENTICATED_FULLY”)
* @Sjabloon()
*/
publiek functie verander nu(Verzoek $verzoek)
{
$params = $request->request->all();
if (!array_key_exists("huidig", $parameters)
|| !array_key_exists("nieuw", $parameters)
|| !array_key_exists("nieuw2", $parameters))
{
terugkeer reeks("Fout" => “Gelieve alle velden in te vullen”);
}
$ em = $ This->container->krijgen(“doctrine.orm.default_entity_manager”);
$gebruiker= $ This->getGebruiker();
$user_encoders= $ This->container->krijgen("beveiliging.encoder_factory")->getEncoder($gebruiker);
$user_repository = $em->getRepository("NaamruimteMyBundle: Gebruiker");
$current_password_encoded = $user_encoders->encodePassword($params["huidig"], $user->getSalt());
$new_password_encoded = $user_encoders->encodePassword($params["nieuw"], $user->getSalt());
if ($user_repository->findOneBy(reeks("wachtwoord" => $current_password_encoded)) == nul) {
terugkeer reeks("Fout" => “Het huidige wachtwoord is verkeerd”);
} elseif ($parameters["nieuw"] != $params["nieuw2"]) {
terugkeer reeks("Fout" => "De twee velden wachtwoord zijn niet hetzelfde");
}
$user->setPassword($new_password_encoded);
$em->persist($gebruiker);
$em->flush();
terugkeer $ This->omleiden($ This->Url genereren("uitloggen", reeks()));
}
|
Als u 1 minuut de tijd neemt om de code te lezen, zult u zien dat deze bijzonder eenvoudig is.
- Eerst controleren we of de drie velden (oud wachtwoord, nieuw wachtwoord en bevestiging) correct zijn ingevuld.
- On voer het wachtwoord in huidige en we vergelijken het met het huidige wachtwoordin de database om te zien of het overeenkomt met het oude ingevoerde wachtwoord.
- We controleren of de "twee" nieuwe wachtwoorden zijn identiques.
- Voer het nieuwe wachtwoord in en duwen in de entiteit.
Activering van zijn account
Deze functie is niet perfect gedetailleerd in andere snippers boven. Het doel is om een gebruiker te deblokkeren die zich net heeft geregistreerd, bijvoorbeeld wanneer hij zijn e-mail heeft gevalideerd. Deze functionaliteit is ontwikkeld op bijna alle platforms die we kennen om verschillende redenen. Om een blokkering van een gebruiker in te stellen, moet u mogelijk ook een provider implementeren.
- blok/accounts beperken nep en spam.
- Verificateur dat de gebruiker een op het eerste gezicht bruikbaar e-mailadres heeft ingevuld.
- Verwijderen rekeningen die na een bepaalde tijd niet zijn gevalideerd.
Workflow
- Een gebruiker meldt zich aan. Zijn account wordt dan geblokkeerd via een voor jou specifiek veld. Dit veld zou dan moeten voorkomen dat hij verbinding maakt zolang dit veld aangeeft dat het account is uitgeschakeld.
1
2
3
4
5
6
7
8
|
// NaamruimteMyBundleEntityUser
klasse Gebruiker {
publiek functie __constructie() {
$ This->token = hasj("sha512", uniqid());
}
...
}
|
1
|
$user->setEnabled(vals);
|
- De gebruiker ontving een e-mail wanneer zijn profiel was doorspoeler in databank. Deze e-mail moet deel uitmaken van een adres dat u genereert.
In deze weg, een token of een unieke identificator moet worden gegeven waarmee de betrokken gebruiker kan worden gevonden. Ik raad je aan om een UUID4 te gebruiken die bedoeld is om willekeurig te zijn. U kunt de lijst met UUID's vinden, evenals de beschrijving van alle versies.
1
2
3
4
|
/ **
* @Weg(“/activeren”, name=”activeren”)
*/
publiek functie activeren()
|
1
|
$ This->Url genereren("activeren", reeks(« token » => $gebruiker->krijgenToken()), waar);
|
Je zou zo'n URL moeten hebben.
1
|
http://hostnaam/activeren?token=mijnUniekToken
|
- De gebruiker opent zijn e-mail en probeert zijn account te activeren door op de verstrekte link te klikken. We gaan dan het onderstaande proces in.
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
|
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/activeren”, name=”activeren”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie activeren(Verzoek $verzoek) {
$params = reeks();
$token = $verzoek->vraag->krijgen(« token »);
$ em = $ This->container->krijgen(“doctrine.orm.default_entity_manager”);
$gebruiker = $em->getRepository("NaamruimteMyBundle: Gebruiker")->vindOneBy(reeks(« token » => $token));
if ($gebruiker != nul) {
$user->setEnabled(waar);
$em->persist($gebruiker);
$em->flush();
$parameters["activeren"] = waar;
} anders {
$parameters["activeren"] = vals;
}
terugkeer $parameters;
}
|
Met dit proces zou u geen probleem moeten hebben om gebruikersaccountvalidatie in te schakelen.
U vindt deze equivalente code op deze 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
|
gebruiken JMSBeveiligingExtrabundelaantekeningVeilig Bestellen;
gebruiken SensioBundelFrameworkExtrabundelConfiguratieMethode;
gebruiken SensioBundelFrameworkExtrabundelConfiguratieweg;
gebruiken SensioBundelFrameworkExtrabundelConfiguratieSjabloon;
gebruiken symfonyBundelFrameworkbundelControllerController;
gebruiken symfonyBestanddeelHttp FoundationAanvraag;
gebruiken symfonyBestanddeelBeveiligingKernBeveiligingContext;
klasse Beveiligingscontroller strekt Controller
{
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/login”, naam=”login”)
* @Sjabloon()
*/
publiek functie Log in(Verzoek $verzoek)
{
$verzoek= $ This->getRequest();
$sessie = $verzoek->getSession();
if ($request->attributen->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributen->get(SecurityContext::AUTHENTICATION_ERROR);
} anders {
$fout = $sessie->get(SecurityContext::AUTHENTICATION_ERROR);
$sessie->verwijderen(SecurityContext::AUTHENTICATION_ERROR);
}
$params = reeks(
"achternaam_gebruikersnaam" => $sessie->get(SecurityContext::LAST_USERNAME),
"Fout" => $fout,
" bericht " => $verzoek->krijgen(" bericht "),
);
if ($request->isXmlHttpRequest()) {
terugkeer $ This-> renderen("GCDirectoryMainBundle:Beveiliging:login-ajax.html.twig", $parameters);
}
terugkeer $parameters;
}
/ **
* @Methode({"NA"})
* @Weg(“/login_check”, name=”login_check”)
*/
publiek functie controle()
{
Gooi nieuwe RuntimeException ('U moet het controlepad configureren dat door de firewall moet worden afgehandeld met behulp van form_login in uw beveiligingsfirewallconfiguratie.');
}
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/uitloggen”, naam=”uitloggen”)
*/
publiek functie uitloggen()
{
Gooi nieuwe RuntimeException ('U moet het uitloggen activeren in de configuratie van uw beveiligingsfirewall.');
}
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/reset”, naam=”reset”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie opnieuw in te stellen() {
terugkeer reeks();
}
/ **
* @Methode({"NA"})
* @Weg(“/ resetten”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
*/
publiek functie nu resetten(Verzoek $verzoek)
{
$params = $request->request->all();
if (!array_key_exists("Log in", $parameters)) {
Gooi nieuwe uitzondering(“Geen login gegeven”);
}
$login = &$params["Log in"];
$ em = $ This->container->krijgen(“doctrine.orm.default_entity_manager”);
$gebruiker = $em->getRepository("NaamruimteMyBundle: Gebruiker")->vindOneBy(reeks("Log in" => $login));
if ($gebruiker == nul) {
terugkeer $ This->omleiden($ This->Url genereren("Log in", reeks()));
}
$ wachtwoord = "mijnWillekeurigWachtwoord";
$user->setPassword($ This->container->krijgen("beveiliging.encoder_factory")->getEncoder($user)->encodePassword($password, $user->getSalt()));
$em->persist($gebruiker);
$em->flush();
terugkeer $ This->omleiden($ This->Url genereren("Log in", reeks()));
}
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/wijzigen”, naam=”wachtwoord wijzigen”)
* @Zeker(rollen=”IS_AUTHENTICATED_FULLY”)
* @Sjabloon()
*/
publiek functie verandering() {
terugkeer reeks();
}
/ **
* @Methode({"NA"})
* @Weg("/wijziging")
* @Zeker(rollen=”IS_AUTHENTICATED_FULLY”)
* @Sjabloon()
*/
publiek functie verander nu(Verzoek $verzoek)
{
$params = $request->request->all();
if (!array_key_exists("huidig", $parameters)
|| !array_key_exists("nieuw", $parameters)
|| !array_key_exists("nieuw2", $parameters))
{
terugkeer reeks("Fout" => “Gelieve alle velden in te vullen”);
}
$ em = $ This->container->krijgen(“doctrine.orm.default_entity_manager”);
$gebruiker= $ This->getGebruiker();
$user_encoders= $ This->container->krijgen("beveiliging.encoder_factory")->getEncoder($gebruiker);
$user_repository = $em->getRepository("NaamruimteMyBundle: Gebruiker");
$current_password_encoded = $user_encoders->encodePassword($params["huidig"], $user->getSalt());
$new_password_encoded = $user_encoders->encodePassword($params["nieuw"], $user->getSalt());
if ($user_repository->findOneBy(reeks("wachtwoord" => $current_password_encoded)) == nul) {
terugkeer reeks("Fout" => “Het huidige wachtwoord is verkeerd”);
} elseif ($parameters["nieuw"] != $params["nieuw2"]) {
terugkeer reeks("Fout" => "De twee velden wachtwoord zijn niet hetzelfde");
}
$user->setPassword($new_password_encoded);
$em->persist($gebruiker);
$em->flush();
terugkeer $ This->omleiden($ This->Url genereren("uitloggen", reeks()));
}
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/register”, name=”registreren”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie registreren()
{
$formulier = $ This->MaakFormulier(nieuwe Gebruikerstype(Gebruikerstype::REGISTREER), nieuwe Gebruiker());
terugkeer reeks(
"formulier" => $form->createView(),
);
}
/ **
* @Methode({"NA"})
* @Weg("/register")
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie Registreer nu(Verzoek $verzoek)
{
$params = $request->request->all()["naam_van_mijn_formulier"];
$formulier = $ This->MaakFormulier(nieuwe Gebruikerstype(Gebruikerstype::REGISTREER), nieuwe Gebruiker());
$formulier->verzenden($verzoek);
if (array_key_exists("plain_wachtwoord", $params) && array_key_exists("plain_password2", $params) && $params["plain_wachtwoord"] == $parameters["plain_password2"]) {
if ($form->isValid()) {
$data = $form->getData();
$data->setPassword($ This->container->krijgen("beveiliging.encoder_factory")->getEncoder($data)->encodePassword($params["plain_wachtwoord"], $data->getSalt()));
$em->persist($data);
$em->flush();
terugkeer $ This->omleiden($ This->Url genereren("Log in", reeks(" bericht " => “Je hebt een e-mail ontvangen om je account te valideren. »)));
}
}
terugkeer reeks(
"fouten" => $params["plain_wachtwoord"] == $parameters["plain_password2"]? $form->getErrors(): reeks(“De twee wachtwoorden moeten hetzelfde zijn”),
"formulier" => $form->createView(),
);
}
/ **
* @Methode({"KRIJGEN"})
* @Weg(“/activeren”, name=”activeren”)
* @Zeker(rollen=”IS_AUTHENTICATED_ANONYMOUSLY”)
* @Sjabloon()
*/
publiek functie activeren(Verzoek $verzoek) {
$params = reeks();
$token = $verzoek->vraag->krijgen(« token »);
$ em = $ This->container->krijgen(“doctrine.orm.default_entity_manager”);
$gebruiker = $em->getRepository("NaamruimteMyBundle: Gebruiker")->vindOneBy(reeks(« token » => $token));
if ($gebruiker != nul) {
$gebruiker->setActive(Gebruiker::ACTIVE_ACTIVE);
$em->persist($gebruiker);
$em->flush();
$parameters["activeren"] = waar;
} anders {
$parameters["activeren"] = vals;
}
terugkeer $parameters;
}
}
|