Toon posts:

Performance rechtensysteem

Pagina: 1
Acties:

Verwijderd

Topicstarter
Voor een website ben ik een rechtensysteem aan het bedenken. Ik heb de volgende tabellen:
code:
1
2
3
4
5
6
7
8
CREATE TABLE `ledenrechten` (
      `userid` int(11) NOT NULL default '0',
      `rechtid` int(11) NOT NULL default '0'
    )
    CREATE TABLE `rechten` (
      `id` int(11) NOT NULL default '0',
      `naam` varchar(50)
    )
Om te kijken of een lid toegang heeft tot een bepaald onderdeel kan ik twee wegen bewandelen:

Weg 1
Ik vul bij het inloggen de array rechten, en bewaar deze in een sessie. De array wordt dan iets als
PHP:
1
$rechten = array('nieuws_lezen', 'nieuws_schrijven', 'forum_lezen', '...etc, etc')
Vervolgens kan ik op de pagina nieuws iets doen als
PHP:
1
2
3
4
5
if (in_array('nieuws_schrijven', $rechten)) {
 // user mag schrijven
}else {
 // user mag niet schrijven
}
Voordeel is dat ik maar 1 keer een query op de database los hoef te laten. Nadeel is dat sommigen na verloop van tijd meer dan 30~40 rechten hebben, die allemaal in die array staan.

Weg 2
Met behulp van MySQL, als een pagina bezocht word:
code:
1
2
3
4
5
SELECT rechten.naam
FROM ledenrechten, rechten
WHERE rechten.id = ledenrechten.rechtid
AND rechten.naam = 'nieuws_schrijven'
AND userid = <<user die pagina bezoekt>>
en dan met mysql_numrows() kijken of er 1 record gevonden is. Als zo, dan kan user schrijven.

Welke performed het best? Een database verbinding wordt op elke pagina sowieso gemaakt.

[ Voor 6% gewijzigd door Verwijderd op 11-04-2005 18:44 ]


  • swampy
  • Registratie: Maart 2003
  • Laatst online: 25-03 09:06

swampy

Coconut + Swallow = ?

Waarom werk je niet in groepen!

Dan heb je gewoon 5-6 groupen met bijbehorende rechten! En kun je uitzonderings gevallen altijd nog special toegang geven!

There is no place like ::1


  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 04-01 15:49

JHS

Splitting the thaum.

Groepen betekend lijkt me dat je ook bij het controleren of iemand iets mag weer een mySQL connectie, namenlijk om te kijken of de groep er rechten tot heeft. Behalve als je dat wil hard-coden, maar dat is niet handig denk ik.. Dus ik denk dat de eerste manier ruim het snelst is. Een array met daarin 40 dingen lijkt me ook niet zo heel zwaar, zoiezo.. Maar de enige manier om het echt te weten is benchmarken :) .

DM!


  • BertS
  • Registratie: September 2004
  • Laatst online: 13-02 08:33
JHS schreef op maandag 11 april 2005 @ 18:57:
Groepen betekend lijkt me dat je ook bij het controleren of iemand iets mag weer een mySQL connectie, namenlijk om te kijken of de groep er rechten tot heeft.
Het maakt toch niets uit of je bij de init de rechten van een enkele gebruiker of van een enkele groep ophaalt? Het enige verschil is imo dat er in de db een (extra) join ligt.

Verwijderd

Topicstarter
JHS schreef op maandag 11 april 2005 @ 18:57:
de enige manier om het echt te weten is benchmarken :) .
Hmm, had ik zelf kunnen bedenken :P

De benchmark was wel overtuigend: op een A64-300+ met 1GB PC3200 geheugen:
code:
1
2
3
Arraytest: 10000 keer - 0.43552 seconden

Sqltest: 10000 keer - 17.066925 seconden
De array bestond overigens uit 200 waarden van 15 tekens.

Lijkt me duidelijk welke ik kies dus :P

Verder kies ik niet voor groepen omdat ik dan sowieso iets moet bedenken voor de uitzonderingen, kan je imo net zo goed meteen per lid bezig gaan. Voor het beheer van de ledenrechten maak ik iets waarbij ik kan kiezen voor een 'standaardpakket' aan rechten, (oftewel een groep ;)), of per lid alle rechten kan aan/uitvinken.

[ Voor 5% gewijzigd door Verwijderd op 11-04-2005 20:54 ]


  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 04-01 15:49

JHS

Splitting the thaum.

bee-es schreef op maandag 11 april 2005 @ 20:46:
[...]Het maakt toch niets uit of je bij de init de rechten van een enkele gebruiker of van een enkele groep ophaalt? Het enige verschil is imo dat er in de db een (extra) join ligt.
Als je het daar gaat ophalen dan schiet je er lijkt me niks mee op, omdat je dan je hele array moet hanteren. En het uitlezen van één enkele row duurt ook niet erg lang, dan is de join lijkt me een stuk minder efficient...

edit:
elguapo: Als ik het goed begrijp kunnen mensen per lid uit standaard paketten kiezen, en wordt dan de hele boel opgeslagen, maar er is dus geen vorm van inheriting en relaties? Dat lijkt me bijzonder inefficient beheren :) . Dan is die ene join wel te verantwoorden...

[ Voor 25% gewijzigd door JHS op 11-04-2005 21:35 ]

DM!


Verwijderd

Topicstarter
Leden krijgen een bepaalde hoeveelheid rechten, die vaak standaard is, maar niet altijd: een user kan een extra recht krijgen of juist een recht minder. Dit leek me de eenvoudigste manier om 't te beheren.

Uiteindelijk komt er natuurlijk een webinterface waarbij je per user vinkjes bij de rechten kan zetten. Als er echt bij veel leden iets moet veranderen kan dat altijd via een script aangepast worden lijkt me.

Maar, ik ben nog niet heel erg ver met bouwen en wel benieuwd: hoe kan ik dezelfde flexibiliteit krijgen en toch met groepen werken?

  • swampy
  • Registratie: Maart 2003
  • Laatst online: 25-03 09:06

swampy

Coconut + Swallow = ?

Okay, dan geef ik in ieder geval een goede reden voor groepen... gelijk voor iedereen in groep 'x' nieuwe rechten toevoegen indien je een nieuwe functie maakt!

There is no place like ::1


  • JHS
  • Registratie: Augustus 2003
  • Laatst online: 04-01 15:49

JHS

Splitting the thaum.

elguapo: Ik denk dat het makkelijkst is om toch een systeem met inhereting te doen. Geef mensen de mogelijkheid om groepen te maken. Als iemand tot een groep behoort, heeft hij al die rechten. Maar als er bij hemzelf nog rechten zijn, overstijgen die de rechten van de groep, zowel in positieve als in negatieve zin. Je kan overwegen om dubbel op te slaan, maar dat levert de bekende risico's op - zeker in dit geval.

Daarom zou ik toch aanraden om dan maar twee queries te draaien per request voor de rechten, een om de hele user op te halen (althans, de relevante zaken, zoals id / name / groep / individuele rechten, template, etc.), en een voor de groep, waar de user in zit. En dan met logica combineren totdat de rechtenarray is gevuld.

Alhoewel dit alles enige performace kan kosten, levert het toch veel voordelen op qua rechtenmogelijkheden :) .

DM!


  • MueR
  • Registratie: Januari 2004
  • Laatst online: 00:06

MueR

Admin Devschuur® & Discord

is niet lief

Ik moet zeggen, dat de TS het meest omslachtige rechtensysteem beschrijft wat ik ooit heb gezien. Je maakt gebruik van 2 tabellen, alleen al om de rechten te lezen. Dan heb je per user ook nog eens een rij of 10 voor alle permissies...
Dit is hoe ik het meestal doe:
code:
1
2
3
4
5
6
Tabel crew_permissions:
UserID
news_admin
faq_admin
member_admin
...

Alle bovengenoemde velden (muv userid), zijn een tinyint met waarde 1 of 0. Je haalt de hele rij van betreffende user uit de DB en slaat dit op in een array, of je haalt een enkele permissie uit de db. Ik doe het laatste. Dit doe ik dmv een functie, welke alleen kijkt op de opgegeven permissie, en TRUE teruggeeft als de waarde 1 (dus allowed) is.

veel minder werk en omslachtig gedoe.

Anyone who gets in between me and my morning coffee should be insecure.


  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 08-05 18:46

Gerco

Professional Newbie

MueR schreef op dinsdag 12 april 2005 @ 04:31:
veel minder werk en omslachtig gedoe.
En toen wilde je pietje rechten geven om nieuws te posten in de sectie "overclocking" en klaasje mag de berichten in het forum "gezeur" niet lezen, maar de rest wel.

In een non triviaal systeem heb je al snel enkele honderden mogelijke rechten die je kunt toekennen, dan gaat een systeem van een kolom per recht echt niet werken (dat van ts is dan ook niet voldoende, maar het komt dichter in de buurt)

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • AW_Bos
  • Registratie: April 2002
  • Laatst online: 08:08

AW_Bos

Liefhebber van nostalgie... 🕰️

Via de search heb ik een handig topic hierover gevonden:
[rml]chem in "[ php/[ my]sql] inherited rechtensysteem"[/rml].
naar mijn idee gebruikt MyReact/React zoiets (herken ik aan de SQL structuur die mijn MyReact testboard gebruikt :P)

[ Voor 11% gewijzigd door AW_Bos op 12-04-2005 09:52 ]

Telecommunicatie van vroeger
🚅Alles over spoor en treintjes


  • VisionMaster
  • Registratie: Juni 2001
  • Laatst online: 17-03 00:12

VisionMaster

Security!

Verwijderd schreef op maandag 11 april 2005 @ 20:52:
[...]
Hmm, had ik zelf kunnen bedenken :P

De benchmark was wel overtuigend: op een A64-300+ met 1GB PC3200 geheugen:
code:
1
2
3
Arraytest: 10000 keer - 0.43552 seconden

Sqltest: 10000 keer - 17.066925 seconden
De array bestond overigens uit 200 waarden van 15 tekens.

Lijkt me duidelijk welke ik kies dus :P

Verder kies ik niet voor groepen omdat ik dan sowieso iets moet bedenken voor de uitzonderingen, kan je imo net zo goed meteen per lid bezig gaan. Voor het beheer van de ledenrechten maak ik iets waarbij ik kan kiezen voor een 'standaardpakket' aan rechten, (oftewel een groep ;)), of per lid alle rechten kan aan/uitvinken.
ik vind dit een slechte performance test, maar wellicht is het goed genoeg voor jou doel. Waarom ik dit vind is,om dat ik denk dat je array test 1x de query uitvoerd op de database en alle andere 9999 pogingen de query uitslag gecached heeft.
Neemt niet weg dat ik zelf had verwacht dat als je de query op de database zou doen, dat je dan sneller geweest had moeten zijn... Misschien met een index op dat je snelheid significant zou veranderen tengunste van de DB uitslag ;-)
Aan de andere kant kan ik me ook bedenken dat een lijstje ontvangen en aflopen alsnog de overhead niet is die je kan verbeteren door beter gebruik te maken van de DB.

I've visited the Mothership @ Cupertino


Verwijderd

Topicstarter
Hmm, denk dat ik toch maar eens met die groepen bezig ga...

Ga ik hiermee de goede kant op:
code:
1
2
3
4
5
6
7
  tabel leden (id, groep, etc, etc,)
  tabel groepen (id, naam)
  tabel rechten (id, naam)

  tabel groepenrechten (groepid, rechtid)
  tabel ledenrechten (lidid, rechtid)
  tabel ledengeenrechten (lidid, rechtid)


En dan in SQL een query waarmee ik de namen van alle rechten ophaal van de groep waar het lid in zit, de eventuele extra rechten van het lid, maar niet als de lidid/rechtid combinatie ook in ledengeenrechten te vinden is.

Begin het zowaar interessante materie te vinden :P

  • swampy
  • Registratie: Maart 2003
  • Laatst online: 25-03 09:06

swampy

Coconut + Swallow = ?

Verwijderd schreef op dinsdag 12 april 2005 @ 11:14:
Hmm, denk dat ik toch maar eens met die groepen bezig ga...

Ga ik hiermee de goede kant op:
code:
1
2
3
4
5
6
7
  tabel leden (id, groep, etc, etc,)
  tabel groepen (id, naam)
  tabel rechten (id, naam)

  tabel groepenrechten (groepid, rechtid)
  tabel ledenrechten (lidid, rechtid)
  tabel ledengeenrechten (lidid, rechtid)


En dan in SQL een query waarmee ik de namen van alle rechten ophaal van de groep waar het lid in zit, de eventuele extra rechten van het lid, maar niet als de lidid/rechtid combinatie ook in ledengeenrechten te vinden is.

Begin het zowaar interessante materie te vinden :P
Mmm, van in de tijd dat ik nog met Acces aan het kloten was ( ICT school ) klopt dit wel aardig... mooie genormaliseerde tabelletjes en groepen gebruiken ;-)

There is no place like ::1


Verwijderd

Topicstarter
Zo, ik ben er uit. Heb t toch iets anders gedaan. Ter leeringh
ende wellicht ter vermaeck:

De tabellen:
code:
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
CREATE TABLE `groepen` (
  `id` int(11) NOT NULL auto_increment,
  `naam` varchar(50),
  PRIMARY KEY  (`id`)
)  ;

CREATE TABLE `rechten` (
  `id` int(11) NOT NULL auto_increment,
  `naam` varchar(50),
  PRIMARY KEY  (`id`)
) ;

CREATE TABLE `ledengeenrechten` (
  `id` int(11) NOT NULL auto_increment,
  `lidid` int(11) NOT NULL default '0',
  `rechtid` int(11) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ;

CREATE TABLE `rechtencombo` (
  `id` int(11) NOT NULL auto_increment,
  `objectid` int(11) NOT NULL default '0',
  `rechtid` int(11) NOT NULL default '0',
  `type` enum('groep','lid'),
  PRIMARY KEY  (`id`)
) ;


Met de volgende query haal ik de rechten op:
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
SELECT rechten.naam
FROM rechten, rechtencombo, leden
WHERE rechten.id = rechtencombo.rechtid
AND 
(
    (
    rechtencombo.type = 'groep'
    AND rechtencombo.objectid = leden.groep
    AND leden.id =<<betreffende userid>>
    )
    OR (
    rechtencombo.type = 'lid'
    AND rechtencombo.objectid = leden.id
    AND leden.id =<<betreffende userid>>
    )
    
)
AND rechtid != 
(
    SELECT rechtid
    FROM `ledengeenrechten`
    WHERE lidid =<<betreffende userid>> 
)
ORDER BY rechten.id

Wellicht kan e.e.a. beter/netter/handiger/sneller, maar dat komt later wel. :P

  • BertS
  • Registratie: September 2004
  • Laatst online: 13-02 08:33
Verwijderd schreef op woensdag 13 april 2005 @ 01:11:
Wellicht kan e.e.a. ...sneller, maar dat komt later wel. :P
Ehm, misschien ff de topictitel checken? :P

Ik zie dat je nu rechten van groep/lid in één tabel hebt gestopt. Waarom neem je 'ledengeenrechten' daar ook niet in op?

Verwijderd

Topicstarter
Is dat een 'beter' datamodel, als ik ledengeenrechten drop en rechtencombo iets als dit laat zijn?
code:
1
2
3
4
5
6
7
8
CREATE TABLE `rechtencombo` (
  `id` int(11) NOT NULL auto_increment,
  `objectid` int(11) NOT NULL default '0',
  `rechtid` int(11) NOT NULL default '0',
  `objecttype` enum('groep','lid'),
  `rechttype` enum('ban','allow'),
  PRIMARY KEY  (`id`)
) ;

offtopic:
Topictitel Schmopictitel :P

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Verwijderd schreef op woensdag 13 april 2005 @ 01:11:
Met de volgende query haal ik de rechten op:
PHP:
1
2
3
4
5
6
7
SELECT rechten.naam
FROM rechten, rechtencombo, leden
WHERE rechten.id = rechtencombo.rechtid
AND 
(  a OR b )
AND rechtid !=  ( sub )
ORDER BY rechten.id

Wellicht kan e.e.a. beter/netter/handiger/sneller, maar dat komt later wel. :P
Die zal in MySQL niet echt geweldig presteren. Om twee redenen; de a OR b moet allebei via één index mogelijk zijn in MySQL wil het snel zijn en dat is ie niet.
Subselects zijn bijna per definitie sloom in MySQL... Overigens is ie ook fout, je kan beter een van deze twee kiezen.
code:
1
2
3
4
5
6
7
AND NOT EXISTS (SELECT sub.rechtid FROM ledengeenrechten sub
    WHERE sub.lidid =<<betreffende userid>> AND sub.rechtid = rechten.id)

of

AND rechten.id NOT IN (SELECT rechtid FROM ledengeenrechten 
     WHERE lidid =<<betreffende userid>> )

Exists is bij kleine hoeveelheden records het snelst, als het goed is. Maar als je alle records toch wilt hebben kan de 2e variant ook goed genoeg werken. Overigens is dat wat je met je eigen query bedoelde.

't Is echter vaak sneller in mysql om het resultaat van de subquery los op te halen en dan de resultaten als getalletjes in je NOT IN te plaatsen. Verder kan je die OR opbreken door met UNION te werken.

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 08-05 14:57
MueR schreef op dinsdag 12 april 2005 @ 04:31:
Ik moet zeggen, dat de TS het meest omslachtige rechtensysteem beschrijft wat ik ooit heb gezien. Je maakt gebruik van 2 tabellen, alleen al om de rechten te lezen. Dan heb je per user ook nog eens een rij of 10 voor alle permissies...
Dit is hoe ik het meestal doe:
code:
1
2
3
4
5
6
Tabel crew_permissions:
UserID
news_admin
faq_admin
member_admin
...

Alle bovengenoemde velden (muv userid), zijn een tinyint met waarde 1 of 0. Je haalt de hele rij van betreffende user uit de DB en slaat dit op in een array, of je haalt een enkele permissie uit de db. Ik doe het laatste. Dit doe ik dmv een functie, welke alleen kijkt op de opgegeven permissie, en TRUE teruggeeft als de waarde 1 (dus allowed) is.

veel minder werk en omslachtig gedoe.
Over normalisatie gesproken |:( Je database moeten aanpassen bij een nieuw onderdeel noem ik nou niet erg efficiënt. Ben wel blij om te horen dat je een tinyint gebruikt, en niet zoals een collega van me een enum('true', 'false'), maar dan nog.
Gebruik liever een koppeltabel met je verschillende rechten. Veel dynamischer.
Pagina: 1