Hi

Ik zit er aan te denken om nog eens wat in PHP te gaan doen. Als basis wil ik eerst en vooral een degelijk 'usermangement system' opzetten. Dit in een object gericht concept.

Omdat hierbij zowel het databaseontwerp als het implementeren van de code zelf belangrijk zijn, zou ik deze graag beiden bespreken.

De database zou ik als volgt willen inrichten:


Misschien kort even het schema toelichten:
In de database wordt over elke gebruiker wat basisgegevens bijgehouden. Er kunnen eventueel een aantal opmerkingen gemaakt worden over een gebruiker. (bv. zijn specifieke functie op de website). Verder is er verplicht een koppeling met de permissies tabel. Uiteraard, behoord een 'permissie-entry' altijd aan 1 specifieke gebruiker. (kleine opmerking hieronder) Verder worden alle belangrijke zaken die een gebruiker uitvoert gelogd. Tot slot is er nog een tabel met sessies in (Ik ben van plan een eigen session handler te programmeren die via de database werkt.) Elke sessie verwijst naar 1 gebruiker.

[opmerking permissies]
Ik overweeg dit nog wat aan te passen, namelijk een toevoeging: groups. Elke gebruiker krijgt dan een group en een group krijgt op zijn beurt een aantal permissies.

In PHP zou ik dan volgende klassen bekomen:
Session, User, Log, Note. Wat deze doen, lijkt mij vanzelfsprekend. Indien dat niet het geval zou zijn, wil ik dit gerust even toelichten.

Graag jullie mening over dit 'model'!
Simpel zal dit inderdaad niet zijn, maar volgens mij wel flexibel. Dan kan ik perfect bepalen welke pagina's welke rechten nodig hebben. Voor de gebruikers van het systeem, lijkt me dit ook prima. Ik kan in de GUI dan door middel van checkboxes laten selecteren wat welke groep mag uitvoeren.

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.
De authentication heeft niks te maken met in/uit loggen. De authentication moet per pagina request kijken wie de bezoeker is: is hij ingelogd of is hij anoniem? Hoe heet hij? Ect? De Authentication maakt dus het User object aan.

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.
Okay Wouter, alleen, je gaat toch niet telkens authentication een user object laten aanmaken? Ik dacht eerder aan het user object te serializen (zie eerder dit topic) en dit in een sessie te plaatsen. (sessie verwerking ga ik wellicht via de database doen)

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?

[size=xsmall]Toevoeging op 29/08/2012 17:42:09:[/size]

Even wel toevoegen dat ik uiteraard authentication wil toepassen, controle is belangrijk. Dus het user object deserializen en nakijken.
Je kan het ook zo doen dat de Authentication kijkt of de sessie bestaat: Zoniet dan wordt de gebruiker geverifieerd en wordt er een User object aangemaakt (die in een sessie wordt geplaatst). Mocht de sessie wel bestaan dan zal de Authentication die User object pakken en kijken of we nog steeds met dezelfde gebruiker te doen hebben.

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![/offtopic]
Alweer bedankt voor de reactie!

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?

[size=xsmall]Toevoeging op 29/08/2012 17:56:04:[/size]

[color=grey]
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.
[/color]
Wat jij wilt met de Authorization is wat je in de Authentication moet doen. Die kijkt wie de gebruiker is, of die nog steeds dezelfde is en dus ook meteen alles van de sessie. Met authorization kijk je wat deze gebruiker mag en of dat gelijk is aan wat er nodig is om iets (pagina, controller, actie) te mogen zien.

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?
Wegens weinig tijd afgelopen week, ben ik nog niet veel verder geraakt. Vandaag ben ik dan meer weer eens verder gaan nadenken hoe ik nu alles over gebruikers flexibel kan bijhouden.

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?

[size=xsmall]Toevoeging op 04/09/2012 19:57:29:[/size]

Ik denk dat ik de oplossing al weet, dadelijk even testen. Eerst eten, ik kom straks terug bij jullie!

[size=xsmall]Toevoeging op 04/09/2012 22:35:05:[/size]

Om er even op terug te komen, mijn idee werkt dus. Even wat test code geschreven:


<?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;
    }

}
?>



<?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'];
    }
}

?>


[/code]
<?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);

?>
[/code]

Reageren