[PHP/CMS] Rechten koppelen aan navigatie?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Mijn cms bestaat uit een aantal modules. Elke module definieert een aantal rechten, bijvoorbeeld "artikelen bekijken", "eigen artikelen veranderen", "alle artikelen veranderen" en "artikelen verwijderen" bij de artikelen module.

Gebruikers worden ingedeeld in groepen. Elke groep heeft een mandje met rechten, toegekend door de beheerder. Zo kan een groep genaamd "docenten" wel artikelen aanmaken, maar ze niet verwijderen.

Laten we bij het voorbeeld van een artikel blijven. Ik wil nu aan het cms een mogelijkheid toevoegen om aan te vinken voor welke groepen een bepaald artikel te lezen is. Stel: je hebt de gebruikersgroepen "leerlingen" en "docenten" en de docent schrijft een artikel bedoeld voor collega's, dan zou hij kunnen aanvinken "artikel alleen te lezen voor docenten". Dat is allemaal geen probleem. Maar nu...

De navigatie is is mijn cms volledig losgekoppeld van de content: elk artikel, nieuwbericht, forum topic, comment, agendapunt etc. dat wordt aangemaakt krijgt een id toegewezen en is te bereiken via dit "node nummer": site.nl/node/23. Als je dus naar url site.nl/node/23 (het docenten-artikel) surft en je hebt niet de goede rechten om artikel te lezen (jouw groep mag ueberhaupt geen artikelen lezen of je bent een leerling), krijg je een "access denied" bericht.

In de navigatie module kun je een schijnbare hierarchie in alle content aanbrengen: onder "Home" zit een link "Opstellen". Onder "Opstellen" maak je een navigatie link "Discriminatie en Racisme" aan. Je heeft als url alias "discriminatie" en als pad "node/23". Vanaf nu is het artikel dat je schreef naast site.nl/node/23 ook te bereiken via site.nl/opstellen/discriminatie. En nu komt het probleem / mijn vragen:
  • Hoe werkt jullie cms op dit gebied? Is het voor een gebruiker niet intuitiever, dat als hij een navigatie-item uitzet, daarmee ook het artikel gelijk onbereikbaar is? (Dat is bij mij dus niet zo. Als je de navigatie link "Discriminatie" verwijdert / uit zet, is node/23 nog steeds te bereiken. Wil je dat artikel unpublishen, moet je dat aangeven op de edit pagina van het artikel zelf
  • Ik heb voor een losse navigatie gekozen omdat dat heel plexibel is: ik kan ook een navigatielink aanmaken naar het pad site.nl/forum/topic/43 of naar http://www.nu.nl of wat dan ook.
  • Ook dacht ik: "als het systeem als eenvoudig intranet wordt ingezet, kan het best zijn dat sommige artikelen niet hierarchisch te plaatsen zijn. Als je dan bij het aanmaken van een nieuw artikel per se een plaats in de hierarchie moet aanwijzen, beperk je de gebruiker. Overigens is er wel een optie om een nieuw artikel meteen aan in de navigatie te zetten, maar het hoeft niet.
  • Stel: de navigatielink "Discriminatie" is voor een leerling onbereikbaar. Toch wordt die link gewoon meegenomen in het renderen van de navigatie zelf. Ik moet dus een manier verzinnen om bij het renderen van het navigatie menu, het intern pad waar elke link naar verwijst (node/23, forum/item/8, node/564) moet controleren op bereikbaarheid voor deze gebruiker en zo niet, dan niet mee te renderen. Is dat niet erg omslachtig?
Ik denk dat mijn hoofdvraag eigenlijk is:
  • Hoe verstandig is het om de navigatie volledig los te koppelen van de content(-pagina's) binnen je cms? Ik hoop op een flink aantal inzichten, want de laatste drie dagen ben ik hier constant over aan het malen geweest en ga ermee in kringetjes :X
offtopic:
Het is misschien handig om te weten dat ik bezig ben met een cms gericht op midden -en kleine bedrijven of afdelingen van grote bedrijven. Ik maak een systeem waarmee snel een eenvoudige website kan worden opgezet, maar een een eenvoudig intranet. Uitbreidbaar met modules (bijvoorbeeld documentenbeheer). Ik wil liever geen discussie over of dat nu wel een goed product is of niet, want ik ben overtuigd van wel :) Dat komt omdat ik voor een aantal klanten Userland Manila heb gekocht en geinstalleerd, en dat was telkens best wel een hit. Mijn systeem ligt dicht tegen dat van hun aan. Ook Manila heeft een losse navigatie van de content, en dat ik 1 van de weinige dingen waar ik bij dat product van het begin over viel. Echter, het bedrijf is al enkele jaren succesvol (en Manila is geschreven door een bekende programmeur uit Sillicon Valley's, Dave Winer, dus die zal het wel weten). Toch ben ik er voor mijn product nog niet uit...

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Je hebt dan eigenlijk 2 opties.

Je zorgt dat, op de plek waar de navigatie structuur wordt opgebouwd, opgegeven kan worden door welke groepen welk item bekeken kan worden. Dat staat dan gewoon los van de rechten van het artikel.

Of je laad, bij het renderen van de navigatie, iedere refererende node op en controleert zo of de huidige gebruiker wel recht heeft om die node te bekijken. In dit geval zou ik toch zeker gaan denken aan het cachen van die output (per groep bv.), omdat het laden van al die nodes toch wel een behoorlijke impact kan hebben op de performance.

Met de laatste methode zou je er voor kunnen kiezen om iedere node een gelijke interface te geven en zo te controleren of de gebruiker rechten heeft (er even vanuit gegaan dat je het OO hebt opgebouwt en php5 gebruikt)

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface Node
{
  public function isAccessableBy(User $user);
}

class ArtikelNode implements Node
{
  public function isAccessableBy(User $user)
  {
    // voer hier de controle uit.
  }
}

$artikelNode = NodeRepository::getNode($IDInNavigatieItem);
if ( $artikelNode->isAccessableBy($currentUser) )
{
  // renderen maar
}


De 2de methode is wat netter natuurlijk, maar wel een stuk trager waarschijnlijk, en heel wat meer prog werk.

Wat ik iig niet zou doen is items in de navigatie laten die niet toegankelijk zijn. Dat is erg verwarrend.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Ricvdp
  • Registratie: Juni 2005
  • Laatst online: 19-09 17:21
offtopic:
Woei, interfaces en variable-type declaratie? Dat zit nog niet in PHP hoor;). Verwar het niet met C# ofzo:). En methods met access-rechten zijn vanaf PHP 5.

[ Voor 16% gewijzigd door Ricvdp op 07-08-2005 09:15 . Reden: toevoegingen ]


Acties:
  • 0 Henk 'm!

  • yiko
  • Registratie: September 2003
  • Laatst online: 20-04 20:19
Ricvdp schreef op zondag 07 augustus 2005 @ 09:14:
offtopic:
Woei, interfaces en variable-type declaratie? Dat zit nog niet in PHP hoor;). Verwar het niet met C# ofzo:). En methods met access-rechten zijn vanaf PHP 5.
offtopic:
Interfaces en type-hinting zitten ook al in PHP5 :)

Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 01:32

alienfruit

the alien you never expected

Jep, en namespaces/packages in PHP 5.1 ;)
Waarvan morgen de RC1 uitkomt met een beetje geluk, als de unicode merge goed gaat :p

[ Voor 52% gewijzigd door alienfruit op 07-08-2005 13:54 ]


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Dank je, Michali. Ik programmeer niet OO, maar het idee is duidelijk. Wel heb ik een vraag die zijdelings hiermee te maken heeft: koppelen jullie navigatie en content ook los in je cms? Bij mij werkt het momenteel zo:
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
27
28
29
30
31
32
33
tabel nodes:

+----+-------+-----------------+--------+--------+
| id | type  | url             | status | access |
+----+-------+-----------------+--------+--------+
|  1 | story |                 |      1 |  1,2,3 |
+----+-------+-----------------+--------+--------+
|  2 | story | fruit           |      1 |  1,2,3 |
+----+-------+-----------------+--------+--------+
|  3 | story | fruit/rood      |      1 |  1,2,3 |
+----+-------+-----------------+--------+--------+
|  4 | story | fruit/rood/kers |      1 |    1,2 |
+----+-------+-----------------+--------+--------+
|  5 | story | groenten        |      1 |    1,3 |
+----+-------+-----------------+--------+--------+
|  6 | story | contact         |      1 |    1,3 |
+----+-------+-----------------+--------+--------+

tabel menu:

+----+-----+
| id | pid |
+----+-----+
|  1 |   0 |
+----+-----+
|  2 |   1 |
+----+-----+
|  3 |   2 |
+----+-----+
|  4 |   3 |
+----+-----+
|  5 |   0 |
+----+-----+

Bij mij kun je een pagina dus een url alias geven, zonder hem op te nemen in de navigatie. Volgens mij werken velen van jullie anders: een pagina wordt automatisch opgenomen in de navigatie. Het is voor een pagina dus niet mogelijk om niet in de content-tree te zitten. Klopt dat?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Hoe refereer je nu dan naar een pagina of node? Lijkt me dat je dan nog een extra kolom nodig hebt in het menu of een aparte associatie tabel. Je zou er ook voor kunnen kiezen om de url kolom in een aparte tabel te zetten en die via een foreign key naar je nodes te laten linken. Zo kun je ook meerdere url's naar 1 node laten verwijzen (of je dat wilt is een 2de, maar je koppelt het wel los en bent weer iets flexibeler).

Zou je trouwens van die access kolom ook niet een aparte tabel maken? Iets als:
code:
1
2
3
4
5
6
CREATE TABLE `node_access`
(
  `node_id` INT UNSIGNED NOT NULL,
  `group_id` INT UNSIGNED NOT NULL,
  PRIMARY KEY (`node_id`, `group_id`)
);


Zelf heb ik alles totaal abstract gemaakt. Ik ondersteun wel tree structuren en link eigenschappen, maar wat er mee gedaan wordt is geheel afhankelijk van degene die er een website mee maakt. Er kan een navigatie mee worden opgebouwt, maar het kan ook voor iets anders gebruikt worden. Het is overigens volledig losgekoppelt van de content die er achter hangt, of waar het naar linkt. Verschillende rechten pas ik nog niet toe, daar ben ik nog niet aan toe gekomen.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
In navolging van Michali heb nu de volgende tabellen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Tabel nav:                 Tabel nav_groups:

+-----+-----+----------+   +-----+-----+
| nid | pid | title    |   | nid | rid |
+-----+-----+----------+   +-----+-----+
|   1 |   0 | Home     |   |   1 |   1 |
+-----+-----+----------+   +-----+-----+
|   2 |   1 | Groenten |   |   1 |   2 |
+-----+-----+----------+   +-----+-----+
|   3 |   1 | Fruit    |   |   1 |   3 |
+-----+-----+----------+   +-----+-----+
                           |   2 |   2 |
                           +-----+-----+
                           |   3 |   1 |
                           +-----+-----+

In de tabel nav staan de pagina's van de website, hierarchisch geordend mbv. een child-parent model. De tabel nav_groups geeft aan welke gebruiksersgroepen een bepaalde pagina mogen bekijken. Om de database load te verminderen haal ik bij elke request eenmalig de hele hierarchie op met de volgende functie:
PHP:
1
2
3
4
5
6
7
8
9
10
// NB: om geen overbodige informatie te geven heb ik een aantal
// kolommen uit de nav tabel weggelaten, zoals weight.

function nav_get_nav() {
  $result = db_query("SELECT * FROM nav ORDER BY pid, weight ASC");

  while ($item = db_fetch_array($result)) {
    $nav[$item['nid']] = $item;
  }
}

Nu wil ik graag de gebruikersgroepen die toegang hebben tot een bepaalde pagina, aan de $nav array koppelen, als volgt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Array
(
    [1] => Array
        (
            [nid] => 1
            [pid] => 0
            [title] => Home
            [access] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )
        )
    [etc...]
)

Ik heb nog maar een beperkte ervaring met ingewikkelder queries dan simpele selects. Ik ben nu zover gekomen:
SQL:
1
2
3
SELECT n.*, ng.* FROM nav n, nav_groups ng 
WHERE n.nid = ng.nid 
ORDER BY n.pid, n.weight ASC

Maar ik loop vast wanneer ik de nav_get_nav functie wil aanpassen om deze resultset te verwerken tot de gewenste array. Misschien gebruik ik ueberhaupt wel een verkeerde query?

[ Voor 102% gewijzigd door Reveller op 09-08-2005 21:43 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
* kick :Y) *

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Vesta
  • Registratie: November 2004
  • Niet online
De query lijkt mij goed. Heb je al het resultaat bekeken van de query? Dat zal namelijk bijna hetzelfde zijn als die van je eerste query, met een extra kolom "rid". In je while loop moet je er voor zorgen dat deze rid's worden geplaatst in de "access" array. Semi-pseudo code:
PHP:
1
2
3
4
5
6
7
8
$nav = array;
while($item = ..){
  if($nav[nid] == null){ // een nieuw nid
    $nav[nid] = $item; // dit is je originele regel
    $nav[nid][access] = array; // definieer access voor nid
  }
  $nav[nid][access][] = $item[rid] // voeg rid toe aan nid
}
Kortom: plaats het item in de navigatie als dat nog niet gedaan is. Voeg vervolgens de rid toe aan het betreffende item. Het is belangrijk dat je controleert of een item al in de navigatie staat. Wanneer je een item overschrijft ben je namelijk de huidige access kwijt..

Let wel op dat items waar niemand rechten heeft zullen ontbreken aangezien je een inner join (SELECT .. FROM a,b) gebruikt. Indien je deze items ook wil ophalen moet je eens kijken naar left joins (SELECT .. FROM a LEFT JOIN b ON ..).

Kijk ook nog even goed naar de naamgeving van je kolommen. nid en rid zijn namelijk vage termen, gebruik liever navigatie_id of rightID.

Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 01:32

alienfruit

the alien you never expected

Als toch niemand rechten heeft tot die nodes, kan je ze toch ook echt weglaten? De gebruiker kan er toch niks mee.

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik heb nu dit, maar er gaat iets goed verkeerd - de query klopt volgens mij (gemaakt nav GoT LEFT JOIN FAQ), maar geeft een raar resultaat terug:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function nav_get_nav() {
  $sql = 'SELECT n.*, nr.rid '.
         'FROM nav n '.
         'LEFT JOIN nav_roles nr ON(n.nid = nr.rid) '.
         'ORDER BY n.pid, n.weight ASC';

  $result = db_query($sql);

  while ($item = db_fetch_array($result)) {
    if($nav[$item['nid']] == null) {
      $nav[$item['nid']] = $item;
      $nav[$item['nid']]['access'] = array();
    }
    $nav[$item['nid']]['access'][] = $item['rid'];
  }
    
  foreach ($nav as $id => $item) {
    $nav[$id]['url'] = trim(nav_item_url($id, $nav), '/');
  }

  return $nav;
}

Het resultaat is dat de 'access' array helemaal niet gevuld wordt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Array
(
    [1] => Array
        (
            [nid] => 1
            [pid] => 0
            [title] => Home
            [rid] => 1
            [access] => Array
                (
                    [0] => 1
                )
        )
)

Waar zit nu de fout? Ik heb regel 14 ook al binnen de if-loop gezet, maar dit maakte weinig verschil :|

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Vesta
  • Registratie: November 2004
  • Niet online
Je join klopt niet.
SQL:
1
ON(n.nid = nr.rid)
moet zijn:
SQL:
1
ON(n.nid = nr.nid)
alienfruit schreef op woensdag 10 augustus 2005 @ 12:27:
Als toch niemand rechten heeft tot die nodes, kan je ze toch ook echt weglaten? De gebruiker kan er toch niks mee.
Ligt eraan wat je ermee wilt doen natuurlijk.. De query haalt de hele hierarchie op, daar horen deze nodes ook bij. Maar in principe zijn ze dan overbodig ja.

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
@Vesta - dank je! Stomme voud. Het werkt nu bijna perfect. Er is nog iets wat niet helemaal werkt / waarvan ik niet snap waarom het gebeurt:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function nav_get_nav() {
  $sql = 'SELECT n.*, nr.rid '.
         'FROM nav n '.
         'LEFT JOIN nav_roles nr ON(n.nid = nr.nid) '.
         'ORDER BY n.pid, n.weight ASC';

  $result = db_query($sql);
  while ($item = db_fetch_array($result)) {
    $nid = $item['nid'];
    
    if ($nav[$nid] == null) {
      $nav[$nid] = $item;
      $nav[$nid]['access'] = array();
    }
    
    $nav[$nid]['roles'][] = $item['rid'];
  }

  return $nav;
}

De array die dit geeft is:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Array
(
    [1] => Array
        (
            [nid] => 1
            [pid] => 0
            [title] => Home
            [rid] => 1 <------ waar komt die vandaan?
            [access] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )
        )
)

Ik snap niet waar de [rid] = 1 in de array vandaan komt. Waarom staat hij daar en hoe zorg ik ervoor dat hij verdwijnt?
alienfruit schreef op woensdag 10 augustus 2005 @ 12:27:
Als toch niemand rechten heeft tot die nodes, kan je ze toch ook echt weglaten? De gebruiker kan er toch niks mee.
Daar heb je gelijk in, maar ik maak graag een onderscheid tussen "niet gevonden" en "toegang geweigerd" pagina's. Stel, jij bent geregistreerd op mijn site en gaat altijd naar site.com/profiel/email om je email te lezen, dan krijg je als je niet ingelogd bent een "toegang geweigerd" bericht. Oh ja, denk je dan ... ff inloggen. Anders denk je misschien "pagina bestaat niet? Ik ging toch altijd naar deze URL voor mijn email"? Het is dan minder duidelijk of jij een foute URL intikt of dat je geen goede rechten hebt...

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Vesta
  • Registratie: November 2004
  • Niet online
die [rid] komt omdat die ook in je query staat (nr.rid), en dus ook in je $item zit. Als je die niet in je array wilt hebben, kun je natuurlijk unset() gebruiken. Een nettere manier is dan in plaats van regel 12-13:
PHP:
1
2
3
4
5
6
$nav[$nid] = array(
  'nid' => $item['nid'],
  'pid' => $item['pid'],
  'title' => $item['title'],
  'access' => array()
);
Zo weet je precies wat er in $nav[$nid] zit.
Pagina: 1