Ontwerpen usermanagement
Pagina: « vorige 1 2 3 4 5 volgende »
Maar goed, even kijken of mijn idee hoe ik het wil uitwerken volgens de 'regels' van OO zijn. Ik zal dit doen a.d.h.v. een korte bespreking wat de functionaliteit is van elke klasse.
Authentication
De gebruiker inloggen / uitloggen. Uiteraard een paar checks invoegen zoals gebanned om gelijk welke reden. Deze methods geven dan iets terug van geslaagd / niet geslaagd (+reden)
Authorization
Is de ingelogde nog wel wie hij/zij zou moeten zijn? Moet er niet gevraagd worden om opnieuw ingelogd te worden?
Permission
Kijken welke permissies nodig zijn voor deze pagina / opvragen welke permissies de gebruiker heeft.
User
Naam bijhouden, user ID, ... Ik vraag me af wat het verstandigste is, een referentie naar de permission class leggen, of de 'rij' bits opslaan?
UserMapper
Zorgt voor de data uitwisseling tussen database en het user object.
Vervolgens hebben we de Authorization die gaat kijken welke rechten er nodig zijn om de pagina te bekijken en kijkt of het User object wel die rechten heeft, zoniet => permission denied, zo ja => pagina laten zien.
Overigens, wil ik bij authorization niet altijd dat per definitie een pagina bekeken mag worden of niet. Ik wil ook de mogelijkheid hebben om delen van een pagina niet te tonen. Denk bijvoorbeeld aan een inkomsten module. Deze staat dan gelijk op het controlepaneel, alleen ik wil niet dat een support medewerker dit kan zien. Anderzijds, wil ik hem andere delen van die pagina niet ontzeggen. Maak ik hiervoor best een apparte class aan, of toch ook hier in?
In welke class zou ik dan het inloggen moeten afhandelen?
Toevoeging op 29/08/2012 17:42:09:
Even wel toevoegen dat ik uiteraard authentication wil toepassen, controle is belangrijk. Dus het user object deserializen en nakijken.
We praten nu met Authentication en Authorization op pagina (route) niveau. Maar je kunt dit natuurlijk met dezelfde 2 klassen ook toepassen op Controller niveau (de inkomsten module wordt door een andere controller gemaakt dan het controlepanel) of zelfs op een action niveau.
Als je de 2 klassen een beetje snel programmeert kun je het voor elkaar krijgen dat je met 2 klassen (authorization en authentication) op elk niveau voor beveiliging kan zorgen. De Authentication zal je 1 keer aanroepen, als eerste, en de authorization zal je misschien vaker aanroepen (mag de user de pagina zien -> ja, mag de user de inkomstenmodule zien -> nee, enz.)
En het inloggen handel je af met een eigen SecurityController oid. Dit is geen taak van een normaal object, maar zul je 'moeten' afhandelen met een Controller.
Offtopic:
Ik heb geen ervaring met Security regeling. Wat ik je hier vertel is hoe het opgelost wordt in het Symfony Framework.
Ik weet niet wat het doel is van dit experiment, maar ik raad je zeker aan ook eens naar een framework te kijken ZF2, Symfony, CakePHP maakt me niks uit. Dan wordt het een stuk makkelijker voor je.
Mocht je dit als doel hebben OO te leren dan kun je natuurlijk vrolijk verder gaan, je leert er echt goed OO door!
Gewijzigd op 29/08/2012 17:49:26 door Wouter J
Maar jij zou dus geen extra klasse Permission maken? Want ik dacht bij authorization controles te doen als, bestaat de sessie nog, is de sessie nog niet vervallen, klopt het IP nog, is de persoon niet op meerdere locaties ingelogd, ... En dan dacht ik emt de Permission klasse effectief na te gaan kijken mag de gebruiker x en y wel doen?
Toevoeging op 29/08/2012 17:56:04:
Offtopic:
In eerste instantie wil ik zelf gewoon een mooie basis uitwerken. Hiermee wil ik dan eigenlijk gelijk welke soort applicatie gaan opbouwen.
Mijn eerste applicatie die ik er werkelijk wil gaan opbouwen is een CMS.
Zelf gebruik ik liever geen framework. Ik wil het liefst alles zelf netjes regelen zoals ik het wil. Ik vind persoonlijk zo'n framework vaak nogal log, en onnodig veel mogelijkheden hebben. Daarom maak ik liever zelf iets, wat ook nog leuk en leerzaam is.
Misschien helpt het als ik de worden even vertaal:
Authentication betekend 'verificatie' hierin verifieer je dus de gebruiker, je zorgt dat je een compleet beeld hebt over wie jou bezoeker is.
Authorization betekend 'machtiging'. Je kijkt of die bezoeker die je net helemaal hebt geschetst wel gemachtigd is om iets te bekijken.
Lees anders even deze tutorial: http://symfony.com/doc/current/book/security.html (totaan 'Using a Traditional Login Form' aangezien het vanaf daar over Symfony gaat)
Rest mij nog een vraag. De permissies in het user object bijhouden of toch maar telkens via de UserMapper ophalen?
Op die opzet zou ik graag wat reacties krijgen, bij deze dus het idee.
De User class wil ik beperkt houden. In een User object zou ik het user_id en de permission_group. Ik twijfel nog een beetje of ik de naam hier ga in bij houden of niet.
Daarnaast wil ik een Person class gaan ontwerpen. Deze moet dan een paar basis gegevens bijhouden zoals de voornaam, achternaam, e-mailadres (e.v.t. nog andere andere algemene zaken, zoals geboortedatum e.t.c.). Eveneens een 'lijst' (array) naar Address, Telephone en Note objecten.
Die laatste drie zijn dus ook classes, wat die juist doen lijkt me duidelijk. Uiteraard, voor elke class die ik noem, zal er ook een Mapper zijn.
Wat denken jullie van deze opzet?
Ik zou het User object de Person klasse laten extenden. Verder klinkt het we goed.
Wouter J op 04/09/2012 18:34:28:
Ik zou het User object de Person klasse laten extenden. Verder klinkt het we goed.
Ik dacht het net omgekeerd te doen. De bedoeling is namelijk dat ik het User object serialize en in de sessie ga stoppen. Dit wil ik dus liefst zo klein mogelijk houden.
Als ik User dus extend, lijkt me dat Person ook zal worden opgenomen?
Toevoeging op 04/09/2012 19:57:29:
Ik denk dat ik de oplossing al weet, dadelijk even testen. Eerst eten, ik kom straks terug bij jullie!
Toevoeging op 04/09/2012 22:35:05:
Om er even op terug te komen, mijn idee werkt dus. Even wat test code geschreven:
Code (php)
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
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
<?php
class Person {
private $firstName;
private $lastName;
private $email;
function __construct($firstName, $lastName, $email) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->email = $email;
}
public function getFirstName() {
return $this->firstName;
}
public function getLastName() {
return $this->lastName;
}
public function getEmail() {
return $this->email;
}
}
?>
class Person {
private $firstName;
private $lastName;
private $email;
function __construct($firstName, $lastName, $email) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->email = $email;
}
public function getFirstName() {
return $this->firstName;
}
public function getLastName() {
return $this->lastName;
}
public function getEmail() {
return $this->email;
}
}
?>
Code (php)
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
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
<?php
class User extends Person implements Serializable {
private $id;
private $permissions_group;
public function __construct(Person $person, $id, $permissions_group) {
parent::__construct($person->getFirstName(), $person->getLastName(), $person->getEmail);
$this->id = $id;
$this->permissions_group = $permissions_group;
}
public function getId() {
return $this->id;
}
public function getPermissions_group() {
return $this->permissions_group;
}
public function serialize() {
return serialize(array(
'id' => $this->id,
'perm' => $this->permissions_group
));
}
public function unserialize($serialized) {
$data = unserialize($serialized);
$this->id = $data['id'];
$this->perm = $data['perm'];
}
}
?>
class User extends Person implements Serializable {
private $id;
private $permissions_group;
public function __construct(Person $person, $id, $permissions_group) {
parent::__construct($person->getFirstName(), $person->getLastName(), $person->getEmail);
$this->id = $id;
$this->permissions_group = $permissions_group;
}
public function getId() {
return $this->id;
}
public function getPermissions_group() {
return $this->permissions_group;
}
public function serialize() {
return serialize(array(
'id' => $this->id,
'perm' => $this->permissions_group
));
}
public function unserialize($serialized) {
$data = unserialize($serialized);
$this->id = $data['id'];
$this->perm = $data['perm'];
}
}
?>
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
session_start();
require_once 'Person.php';
require_once 'User.php';
$person = new Person('Write', 'Down', '[email protected]');
$user = new User($person, 7, 1);
echo $user->getFirstName(); //geeft perfect Write
$_SESSION['user_data'] = serialize($user);
print_r($_SESSION);
?>
session_start();
require_once 'Person.php';
require_once 'User.php';
$person = new Person('Write', 'Down', '[email protected]');
$user = new User($person, 7, 1);
echo $user->getFirstName(); //geeft perfect Write
$_SESSION['user_data'] = serialize($user);
print_r($_SESSION);
?>
Gewijzigd op 04/09/2012 22:43:04 door Write Down
Dit is geen grote ramp, maar toch... Bij het inloggen bijvoorbeeld, heb ik totaal geen behoefte aan de gegevens van een persoon. Toch moet ik deze ophalen, wat dus onnodige queries kost. En nee, deze info wil ik niet gaan opslaan in de sessie, net omdat ik het zo weinig nodig heb.
Daarom overweeg ik het niet Person te extenden, maar User. Alleen weet ik niet of dit echt een goede oplossing is. Het klinkt in elk geval niet erg logisch. Graag jullie raad!
En als User niet hetzelfde is als Person, waarom moeten ze dan 1 op 1 gelinkt worden?
Persoonlijk zou ik user_id en person_id gewoon als relatie beschouwen, maar dan alleen als je dat nodig hebt.
Person extend dus User.
User = id, loginnaam (kan ook email zijn), wachtwoord, sessie en rechten
Person = id, naam, email, leeftijd (en andere profiel-dingen)
Verder heb je het denk ik wel meer over de database kan dan de PHP kant lijkt mij. Want ik zie bijvoorbeeld niet in waarom ik het wachtwoord in een User object zou opslaan.
Write Down op 07/09/2012 11:21:53:
Dit is geen grote ramp, maar toch... Bij het inloggen bijvoorbeeld, heb ik totaal geen behoefte aan de gegevens van een persoon. Toch moet ik deze ophalen, wat dus onnodige queries kost. En nee, deze info wil ik niet gaan opslaan in de sessie, net omdat ik het zo weinig nodig heb.
Waarom moet je die gegevens ophalen?
Moeten is een groot woord. Ik kan null etc invullen, maar goed. Dan zit ik alsnog met een ongewenst / onnodig object. Als ik het er volledig uit sloop, dan kan ik even goed niet langer extenden.
Write Down op 07/09/2012 11:31:57:
Want ik zie bijvoorbeeld niet in waarom ik het wachtwoord in een User object zou opslaan.
Omdat een user/gebruiker moet kunnen inloggen met een wachtwoord?
Die hoef/mag je uiteraard niet opslaan in een sessie, maar om te wijzigen etc wel.
Was ook maar een voorbeeld: wellicht logged_in BOOLEAN is beter ;).
Code (php)
De class User extends de class Person en je moet er nog een meegeven in de constructor. Dat is iets wat overbodig is en wat je nooit zou moeten doen. Alle data/methods die je nodig zou kunnen hebben in de class User heb je al, dus waarom nog eens meegeven?
Je zou je moeten afvragen of dat extenden uberhaupt nodig is.
Toevoeging op 07/09/2012 11:58:42:
En nog even terug naar een al wat oudere opmerking van je, maar mogelijk nu weer relevant.
Write Down op 04/09/2012 19:03:32:
Ik dacht het net omgekeerd te doen. De bedoeling is namelijk dat ik het User object serialize en in de sessie ga stoppen. Dit wil ik dus liefst zo klein mogelijk houden.
Dat maakt niet uit. Bij het serializen bepaal je zelf welke gegevens je meeneemt. Zelfs al heb je 10MB aan data in het object zitten, als jij alleen het id van het object wil serialiseren dan kan dat natuurlijk.
Daarom ook dat ik vraag, wat is volgens jullie de beste oplossing?
Wat betreft serialize, dit had ik inderdaad intussen ook al door, zie ook voorbeeld code.
Maar of het wel of niet moet is vanaf een afstand niet of nauwelijks te beantwoorden.
Stel jezelf eens de vragen:
- is Person dezelfde entiteit als User?
- is User dezelfde entiteit als Person?
- heb je de gegevens/methodes van User nodig in Person?
- heb je de gegevens/methodes van Person nodig in User?
- kan je gegevens/methodes die je in beide nodig hebt uitfilteren en wellicht in een gemeenschappelijke class onderbrengen?
Ik zit nog steeds een beetje met een twijfel of ik ze nu al dan niet ga uit mekaar trekken. Ik wil nl. de mogelijkheid hebben om 'losse' personen aan te maken. Denk bijvoorbeeld aan het toevoegen van contactpersonen aan de applicatie. Ik zou bijvoorbeeld kunnen bijhouden wie mijn contactpersoon bij mijn hosting is. Die persoon is dus eigenlijk totaal geen gebruiker.
Anderzijds, is een gebruiker sowieso een persoon. Als ik iemand als gebruiker toevoeg, zou ik ook graag wat informatie over die persoon willen bijhouden. Vanuit dat punt, ben ik er vanuit gegaan dat er eigenlijk wel een relatie 'moet' zijn tussen beide klassen.
Verder ben ik vrij zeker dat de kans dat ik meer gebruikers (die dus ook 'persoon' zijn) heb dan enkel en alleen personen. Daarom dus toch nog enige twijfel.