[PHP] Tijdelijke privilege opslaan

Pagina: 1
Acties:

Onderwerpen


  • DDemolition
  • Registratie: Augustus 2003
  • Laatst online: 30-09-2024

DDemolition

slopen is mijn lust en leven

Topicstarter
Hoi,

Ik heb al een werkende oplossing, maar wil eigenlijk een sneller stukje code.
Het gaat om het volgende:
Ik heb een loginsysteem waarbij gebruikers verschillende acties uit kunnen voeren.
De tabelstructuur ziet er dan als volgende uit:
Gebruiker <-> Classes <-> Acties
Afbeeldingslocatie: http://rene.dekkers.biz/Plaatjes/userpolicy.JPG

Ik heb nu een functie geschreven waarbij bij elke actie (vrijwel elke actie dus) gekeken word of de gebruiker of de betreffende actie toegestaan is. Dit is dus ongeveer zoiets als
PHP:
1
2
//Geeft true of false terug
Is_Allowed($UserID, $ActionName)


Nu moet bij elke klik misschien 5x deze functie uitgevoerd worden. hierbij moet de database 4 tabellen doorworstelen wat niet echt bevordelijk is voor de preformance...

Nu is de vraag:
Zou ik iets tijdelijks aan kunnen maken bij elke login?
Het is niet zo erg dat een gebruiker een keer opnieuw moet uit en inloggen om een actie toegewezen te krijgen. Dit is onder Windows immers ook zo.
Ik heb al zitten denken om alles in een session te vrotten, maar weet niet precies hoe.
Wie kan mij nuttige tips geven?

Specs: Server, WS boven, WS beneden


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Kun je niet een functie maken die een array met actions accepteert?
PHP:
1
Is_Allowed($UserID, array('post', 'edit', 'update', 'delete'))

Je kan dan met een enkele query alle actions in één keer checken (met IN ;)) en een array returnen met daarin de rechtenset.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
DDemolition schreef op donderdag 15 december 2005 @ 15:41:
Ik heb al zitten denken om alles in een session te vrotten, maar weet niet precies hoe.
Wie kan mij nuttige tips geven?
Nou, frot alles in een sessie. Wat snap je precies niet dan? Een sessie is weinig anders dan een hashtable waar je keys en variabelen in kunt zetten. Je kunt ook hele arrays in een sessie stoppen. Iets als:
$user_rights = GetRights($username)
$_SESSION["user_rights"] = $user_rights;

Als de userrights niet aanwezig zijn in een sessie, haal je ze op uit de DB, en dan kun je de rest van de user-sessie gebruik maken van de data in de sessie i.p.v. steeds op de DB toe te moeten grijpen.
-NMe- schreef op donderdag 15 december 2005 @ 15:54:
Je kan dan met een enkele query alle actions in één keer checken (met IN ;)) en een array returnen met daarin de rechtenset.
Moet 'ie nog steeds iedere keer de DB benaderen, lost IMHO dus weinig op.

[ Voor 19% gewijzigd door Hydra op 15-12-2005 15:59 ]

https://niels.nu


Verwijderd

Misschien 1 x een lijst met acties ophalen die valide zijn en deze in de session plaatsen.
Hiermee gaan vergelijken met de function is_allowed(). Hiermee hoef je alleen maar de database te raadplegen bij het in en uitloggen.

  • DDemolition
  • Registratie: Augustus 2003
  • Laatst online: 30-09-2024

DDemolition

slopen is mijn lust en leven

Topicstarter
Hydra schreef op donderdag 15 december 2005 @ 15:57:
[...]
Nou, frot alles in een sessie. Wat snap je precies niet dan? Een sessie is weinig anders dan een hashtable waar je keys en variabelen in kunt zetten. Je kunt ook hele arrays in een sessie stoppen. Iets als:
$user_rights = GetRights($username)
$_SESSION["user_rights"] = $user_rights;

Als de userrights niet aanwezig zijn in een sessie, haal je ze op uit de DB, en dan kun je de rest van de user-sessie gebruik maken van de data in de sessie i.p.v. steeds op de DB toe te moeten grijpen.
Dat bedoel ik ook eigenlijk ja,
Zo klinkt 't wel vrij simpel ja....

Dus krijgt als het ware:

Tijdens login:
Alle acties die aan gebruiker zijn toegewezen in sessie stoppen (als array)

Tijdens aanroepen van privilege:
Kijken of actie in array aanwezig is. "true" of "false" returnen

Vreet dit geheugen op de server of blijft het allemaal tijdelijk in de 'sessiondata' map staan?

[ Voor 4% gewijzigd door DDemolition op 15-12-2005 16:15 ]

Specs: Server, WS boven, WS beneden


  • TRON
  • Registratie: September 2001
  • Laatst online: 16-09 13:13
Dat blijft in de 'sessiondata' map staan.

Het nadeel van deze oplossing is, dat als iemand ingelogd is en jij wijzigt de rechten, dat de rechtenwijziging pas doorgevoerd wordt als iemand opnieuw inlogd. Dit kan een negatieve bijwerking hebben als je bijvoorbeeld van iemand heel snel rechten wil verwijderen omdat er misbruik gemaakt wordt of iets dergelijks.

Leren door te strijden? Dat doe je op CTFSpel.nl. Vraag een gratis proefpakket aan t.w.v. EUR 50 (excl. BTW)


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
Even ongehinderd door kennis van hoe sessies zijn geimplementeerd in PHP, maar waar komt de sessiedata dan vandaan. Het lijkt me dat deze alsnog uit een database of textfile moeten komen. Je zit dus sowieso vast aan relatief trage methode om de rechten op te halen. Als je niet al gebruik maakt van sessies zie ik niet helemaal het voordeel boven een "lazy loading" implementatie die alle rechten van de user uit de DB vist op het moment dat de eerste check wordt uitgevoerd.

Regeren is vooruitschuiven


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
T-MOB schreef op donderdag 15 december 2005 @ 16:32:
Even ongehinderd door kennis van hoe sessies zijn geimplementeerd in PHP, maar waar komt de sessiedata dan vandaan. Het lijkt me dat deze alsnog uit een database of textfile moeten komen. Je zit dus sowieso vast aan relatief trage methode om de rechten op te halen. Als je niet al gebruik maakt van sessies zie ik niet helemaal het voordeel boven een "lazy loading" implementatie die alle rechten van de user uit de DB vist op het moment dat de eerste check wordt uitgevoerd.
klopt maar dit gebeurd 1x, en niet voor elke klik
sessiedata blijft tijdens de hele sessie beschikbaar, gewone vars moet je opnieuw vullen of meegeven als parameters (post of get)

[ Voor 11% gewijzigd door BasieP op 15-12-2005 16:36 ]

This message was sent on 100% recyclable electrons.


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
BasieP schreef op donderdag 15 december 2005 @ 16:36:
[...]
klopt maar dit gebeurd 1x, en niet voor elke klik
sessiedata blijft tijdens de hele sessie beschikbaar, gewone vars moet je opnieuw vullen of meegeven als parameters (post of get)
Dat de data beschikbaar blijft snap ik. Maar op de server moet die data dus de hele sessie "ergens" worden opgeslagen om in elke pagina beschikbaar te zijn. Het lijkt me stug dat dit in het geheugen van de server gebeurt waardoor dus alsnog alle gegevens op een bepaalde manier van de schijf moeten worden gelezen bij elke klik.
Als je al met een sessie werkt moet sowieso al naar de sessie-data worden gezocht, dan kan ik me wel wat aan voordeel voorstellen. Werk je nog niet met sessies dan vraag ik me af of het loont om hier een sessie voor in te zetten. Zou het daadwerkelijk sneller zijn dan op elke pagina waar je rechten nodig hebt in 1 query alle (benodigde) rechten ophalen?

Regeren is vooruitschuiven


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
T-MOB schreef op donderdag 15 december 2005 @ 17:56:
[...]

Dat de data beschikbaar blijft snap ik. Maar op de server moet die data dus de hele sessie "ergens" worden opgeslagen om in elke pagina beschikbaar te zijn. Het lijkt me stug dat dit in het geheugen van de server gebeurt waardoor dus alsnog alle gegevens op een bepaalde manier van de schijf moeten worden gelezen bij elke klik.
Als je al met een sessie werkt moet sowieso al naar de sessie-data worden gezocht, dan kan ik me wel wat aan voordeel voorstellen. Werk je nog niet met sessies dan vraag ik me af of het loont om hier een sessie voor in te zetten. Zou het daadwerkelijk sneller zijn dan op elke pagina waar je rechten nodig hebt in 1 query alle (benodigde) rechten ophalen?
1 woord: JA
zeker bij grote db's

trouwens worden sessies volgens mij wel in het geheugen gelaten voor een korte periode. en dan pas weggeschreven

This message was sent on 100% recyclable electrons.


  • DDemolition
  • Registratie: Augustus 2003
  • Laatst online: 30-09-2024

DDemolition

slopen is mijn lust en leven

Topicstarter
Ik neem aan dat dit:
- check of actie in array staat -> true of false
sneller gaat als:
- connecten naar de database -> in array stoppen met overbodige data -> check of het mag -> true of false geven.

Het inloggen laat ik even buiten zich. Dit boeit me niet zo veel of dit +- 2-3 sec. duurt...

Verder zou ik bij elk speciaal event een Push_Privileged uit kunnen voeren. (zo gaat denk ik mijn 'acties naar array' functie heten).

[ Voor 22% gewijzigd door DDemolition op 15-12-2005 18:56 ]

Specs: Server, WS boven, WS beneden


  • stekkel
  • Registratie: Augustus 2001
  • Laatst online: 17-09 08:05
Wanneer je de rechten via het zelfde programma kan veranderen zou ik ergens een timestamp neerzetten en deze timestamp bij elke verandering van rechten updaten. Na de sessionload kan je dan snel checken of de gecachde privileges nog steeds geldig zijn. Uiteraard moet je dan ook de timestamp laden op het moment dat je de privileges voor de eerste keer in de sessie cached.

[ Voor 8% gewijzigd door stekkel op 15-12-2005 19:32 ]


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
DDemolition schreef op donderdag 15 december 2005 @ 18:54:
Ik neem aan dat dit:
- check of actie in array staat -> true of false
sneller gaat als:
- connecten naar de database -> in array stoppen met overbodige data -> check of het mag -> true of false geven.
Tuurlijk maar de data staat nog niet in een array, eerst moet je sessiedata uitgelezen worden. Ik heb vanavond geen tijd, maar misschien dat ik dit morgen wel even ga benchmarken. Meten is immers weten en een argument waarom een sessie performanter zou zijn heb ik nog niet gehoord.

Regeren is vooruitschuiven


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
T-MOB schreef op donderdag 15 december 2005 @ 19:42:
[...]

Tuurlijk maar de data staat nog niet in een array, eerst moet je sessiedata uitgelezen worden. Ik heb vanavond geen tijd, maar misschien dat ik dit morgen wel even ga benchmarken. Meten is immers weten en een argument waarom een sessie performanter zou zijn heb ik nog niet gehoord.
um dat data in die session zette is een questie van 1 query.
daarna (als het eenmaal geset is) duurt zoiets 0.00001 sec ofzo.. te verwaarlozen dus. terwijl een query op een grote DB al gauw 0.02-0.1 secs kost

This message was sent on 100% recyclable electrons.


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
BasieP schreef op donderdag 15 december 2005 @ 19:43:
um dat data in die session zette is een questie van 1 query.
daarna (als het eenmaal geset is) duurt zoiets 0.00001 sec ofzo.. te verwaarlozen dus. terwijl een query op een grote DB al gauw 0.02-0.1 secs kost
Als mijn eigenwijsheid begint te irriteren roep je het maar, maar waar haal je deze cijfers vandaan. Met sessies moet bij elke request:
1. het juiste sessiebestand worden opgesnord
2. alle variabelen worden gedeserialised
Ik geloof niet dat dit in 0.00001s mogelijk is.
Voordelen van disk-cache en ander memory-management heb je in een database ook. Waarschijnlijk nog beter dan in een standaard filesystem omdat de DB specifiek voor zijn taak gemaakt is.

Deze overhead van sessies is bovendien niet alleen beperkt tot pagina's waar je de data nodig hebt. Nadat een sessie is gestart worden bij elke request de variabelen ingelezen. Maar then again, morgen test ik het wel even.

Regeren is vooruitschuiven


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
T-MOB schreef op donderdag 15 december 2005 @ 20:05:
[...]

Als mijn eigenwijsheid begint te irriteren roep je het maar, maar waar haal je deze cijfers vandaan. Met sessies moet bij elke request:
1. het juiste sessiebestand worden opgesnord
2. alle variabelen worden gedeserialised
Ik geloof niet dat dit in 0.00001s mogelijk is.
Voordelen van disk-cache en ander memory-management heb je in een database ook. Waarschijnlijk nog beter dan in een standaard filesystem omdat de DB specifiek voor zijn taak gemaakt is.

Deze overhead van sessies is bovendien niet alleen beperkt tot pagina's waar je de data nodig hebt. Nadat een sessie is gestart worden bij elke request de variabelen ingelezen. Maar then again, morgen test ik het wel even.
getallen zijn educated guesses adhv eigen ervaring, maar ik zou graag een officiele benchmark zien hoor, denk alleen niet dat er veel verrassende resultaten uit komen.

(trouwens moet je dan vooral letten op de grote van de DB en de complexicteit van je query)

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
T-MOB schreef op donderdag 15 december 2005 @ 20:05:
Als mijn eigenwijsheid begint te irriteren roep je het maar, maar waar haal je deze cijfers vandaan. Met sessies moet bij elke request:
1. het juiste sessiebestand worden opgesnord
Gelukkig niet. Sessie data wordt over het algemeen in-memory gehouden.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 21-09 02:21

Janoz

Moderator Devschuur®

!litemod

Hydra schreef op vrijdag 16 december 2005 @ 10:33:
[...]


Gelukkig niet. Sessie data wordt over het algemeen in-memory gehouden.
Hoe kom je daarbij?

PHP heeft enkel een page scope. Elk paginarequest wordt appart behandeld en ze hebben geen enkele notie van elkaar. Er is dus geen application scope om hierin bv een map met sessions bij te houden. Aan het eind van je script wordt de boel naar de schijf geschreven, en aan het begin weer ingeladen. Enige 'versnelling' hierin is eventueel het cachen van het file system.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • DDemolition
  • Registratie: Augustus 2003
  • Laatst online: 30-09-2024

DDemolition

slopen is mijn lust en leven

Topicstarter
Ik zal in de loop van de dag of vanavond eens een performance test doen. Mijn heeft rechten check zal gegarandeerd nog niet perfect zijn, dus misschien moet ik deze een beetje herschrijven.

Specs: Server, WS boven, WS beneden


Acties:
  • 0 Henk 'm!

Verwijderd

Dit klink exact als een topic wat ik een hele tijd geleden had geopend.

Methodieken voor snelle permissie controle

In principe wil je op een heel snelle manier controleren of de context voldoet aan een benodigde permissie. :)

[ Voor 6% gewijzigd door Verwijderd op 16-12-2005 11:21 ]


Acties:
  • 0 Henk 'm!

  • DDemolition
  • Registratie: Augustus 2003
  • Laatst online: 30-09-2024

DDemolition

slopen is mijn lust en leven

Topicstarter
Verwijderd schreef op vrijdag 16 december 2005 @ 11:19:
Dit klink exact als een topic wat ik een hele tijd geleden had geopend.

Methodieken voor snelle permissie controle

In principe wil je op een heel snelle manier controleren of de context voldoet aan een benodigde permissie. :)
Op zich hetzelfde principe.

Het idee met een timestamp is nog niet zo verkeerd. Ik denk dat alle beschikbare acties in 'n array zetten en vervolgens bij het uitvoeren zelf een check doen of de betreffende actie in de array staat wel aardig is.

Naam mijn idee is dit één van de snelste manieren. Misschien dat ik wel wat in de knoop kom met acties die alleen tussen bepaalde tijd uitgevoerd kunnen worden....
hiervoor zou ik nog een handeling meer moeten doen om à la minute te weten of de actie mag of niet.

[ Voor 7% gewijzigd door DDemolition op 16-12-2005 13:02 ]

Specs: Server, WS boven, WS beneden


Acties:
  • 0 Henk 'm!

Verwijderd

Het is gewoon een verrot lastig topic. Zeker als je zit met objecten die een rechtenstructuur kunnen overerven van verschillende parents, en je ook nog een flexibel rechten systeem aanwezig hebt.

Het liefst wil je bij elke query die je uitvoert de context meegeven van de client en direct in de query een criteria toepassen. Het is in feite wel de beste manier omdat je dan ook geen overbodige informatie gaat teruggeven die onvoldoende rechten heeft.

De enige manier om dit echt goed voor elkaar te krijgen is

a) Alleen permissies van een object controleren als ze er zijn. Dus bij het ophalen van een object een bool, hasPermissions of iets derg. Als ze er niet zijn gaat de Chain Of Responsibility in en pakt het eerstvolgende parent object de vereiste permissies op.
b) Een lookup table, waarbij je snel een overzicht krijgt van de benodigde permissies voor de desbetreffende context. Deze hoeft alleen aangesproken te worden als hasPermissions positief is. Echter bij elke change in relatie tot permissies zul je deze tabel moeten updaten.

En dan moet je voor jezelf nog afwegen of je alleen de toegestane objecten wilt teruggeven, en dus in de query al op permissies wil filteren, of pas later de objects wilt filteren op permissies.

[ Voor 49% gewijzigd door Verwijderd op 16-12-2005 14:44 ]


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
BasieP schreef op donderdag 15 december 2005 @ 20:13:
[...]
getallen zijn educated guesses adhv eigen ervaring, maar ik zou graag een officiele benchmark zien hoor, denk alleen niet dat er veel verrassende resultaten uit komen.
Nou, de benchmark is voltooid en ik denk dat er voor jou best verrassende resultaten uit zijn gekomen. Om te testen heb ik een database je aangemaakt met vijf tabellen:
users (userid, name), PK op userid
groups (groupid, name), PK op groupid
actions (actionid, name), PK op actionid
user_groups (userid, groupid), PK over beide kolommen,
group_actions (groupid, actionid, allowed), PK over groupid en actionid
session
Een relatie in group_actions betekent dat voor de groep een actie toegestaan is als allowed op 1 staat. Een 0 in deze kolom betekent een expliciete "deny" op de actie. De tabel heb ik gevuld met random data, waarbij zijn aangemaakt: 20.000 users, 300 actions en 75 groepen. Een user is lid gemaakt van gemiddeld 12 groepen en voor elke groep zijn gemiddeld 40 relaties aangemaakt in de group_actions tabel.
Om alle acties op te halen waarop een user rechten heeft voeren we dan de volgende query uit:
SQL:
1
2
3
4
5
6
SELECT name FROM actions AS a
        INNER JOIN group_actions AS ga ON (a.actionid = ga.actionid)
        INNER JOIN user_groups AS ug ON (ga.groupid = ug.groupid)
        WHERE userid = [testinteger]
        GROUP BY name
        HAVING MIN(ga.allowed) = 1

Het duizend maal op halen van alle rechten van user 1 duurde op een PIII 800 / Debian / PHP4 / MySQL4 op reiserFS minder dan een seconde. Gemiddelde querytime van minder dan 1ms dus. Met sessies id het iets lastiger om 1000 maal te testen. Om dit toch mogelijk te maken heb ik verschillende scripts gemaakt.
Een createSession.php die een sessie aanmaakt, de rechten opslaat in de sessie en vervolgens het sessieid echoed.
Een readSession.php die de rechtenarray uitleest uit de sessie ($array=$_SESSION['rights']) en vervolgens 1 echoed.
Een readDB.php die het rechtenarray uit de DB haalt en 1 echoed.
Een overheadTest.php die alleen maar een 1 echoed om te kijken hoeveel request overhead er is.

Vanuit het benchmark maak ik nu met behulp van het eerste script een sessie aan. Naar de overige scripts doe ik duizend maal een request om te kijken hoe lang elke methode duurt. De simpelste resultaten:
On 1000 repetitions, de total request time is:
SESSIONS: 4.72627282143s
DB      : 7.69997811317s
Req Ovh : 3.31172513962s

Haal je de request overhead van de overige tijden af dan kun je concluderen dat de sessiemethode ongeveer 3 maal zo snel is als een database request. Die resultaten kunnen echter niet kloppen daar het uitvoeren van de query slechts 1 seconde duurde voor duizend herhalingen. Een verschil van meer dan een seconde kan dus niet alleen voortkomen uit het verschil in methode. De overhead om uberhaupt de query uit te kunnen voeren - databaseconnectie - is in een real-world situatie waarschijnlijk sowieso nodig. We passen de scripts aan zodat ze exact hetzelfde zijn op de methode om het array te vullen na:
On 1000 repetitions, de total request time is:
SESSIONS: 7.00083088875s
DB      : 7.26760101318s
Req Ovh : 3.33685708046s

Uitgaande van 1 seconde voor de DB methode beteknt dit dat de sessie-methode ongeveer .26s sneller is bij 1000 herhalingen. De database methode is daarmee ongeveer 35% duurder, maar levert wel een aantal voordelen:
- Je rechten zijn altijd up to date (je hoeft dus geen updatemechanisme te verzinnen of uitvoeren)
- Je hebt de overhead alleen wanneer je daadwerkelijk gaat gebruiken
- Je hebt geen last van filesystem beperkingen, ik heb nu slechts enkele sessiebestanden op mijn testbakje staan. Bij duizenden users die mogelijk op meerdere PC's een sessie hebben lopen kan je FS wel eens een stuk minder performant gaan werken.
Van een verschil in de verhouding 0.01:0.00001 is er in geen geval sprake.

test scripts

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

  • DDemolition
  • Registratie: Augustus 2003
  • Laatst online: 30-09-2024

DDemolition

slopen is mijn lust en leven

Topicstarter
Damn, je hebt er wel werk van gemaakt _/-\o_ _/-\o_
Ik was al net bezig met het schrijven van de te benchmarken scripts, maar je was me overduidelijk voor!

Als ik het goed begrijp wordt het zaakje waarschijnlijk langzamer als er veel gebruikers sessies open hebben staan met een 'direct DB' systeem.
Een feit is wel dat de DB server veel SQL statements moet behandelen wat veel CPU kracht vereist. Ook is het me opgevallen dat het draaien van moeilijkere php stukken veel CPU eist..
Dit heb je met een sessie controle minder. Mij lijkt dat juist CPU en geheugen zwaar belast zullen worden en het met de schrijfbewerkingen wel mee valt.

Specs nog even:
Athlon 64 2800+
Sata Raid 1 (2x Raptor)
2x 512MB 3200 modules
PHP5.0.4
MySQL 5.1
OS wordt nog over getwist..
(Tijdens het testen en developpen Windows 2003 Enterprise ed. + IIS 6)

edit:
Ik denk dat er maximaal +- 200 gebruikers op het systeem zitten met ongeveer maximaal +- 75 gebruikers actief

[ Voor 12% gewijzigd door DDemolition op 16-12-2005 20:00 ]

Specs: Server, WS boven, WS beneden

Pagina: 1