Felhasználói jogosultságok kezelése – CakePHP 1. rész

cakephpMinden komolyabb webalkalmazás fejlesztése során egy igen lényeges momentum a felhasználók hozzáférésének, jogainak kezelése. Annak szabályozása, hogy ki mihez férjen hozzá nem csak biztonsági, hanem működtetési szempontból is fontos. Meglehetősen sok leírás található arról angolul, hogy a problémát hogyan kezeljük a CakePHP keretrendszer használata esetén, de ezek nagy része már elavult vagy csak rész igazságokat közöl. Most itt megpróbálom felszolgálni a teljes sütit.

Amit tudnod kell

Nem fogok arról most írni, hogy mi is a cakephp, a bejegyzés feltételezi, hogy tisztában vagy vele és van egy friss (1.2.3.8166 Stable) és működő cake telepítésed. Nem fogok itt belemenni abba, hogy mi a hitelesítés, sem az ACL alapjairól nem fogok beszélni. Kérlek ha ezeket még nem kóstoltad meg, akkor használd a linkeket és gyere vissza utána.
Elöljáróban csak annyit szeretnék itt megjegyezni, hogy habár sok leírás a felhasználói jogosultság kezelést egyenlőnek látja az ACL használatával a helyzet cseppet sem ez.

Előfeltételek

Ahhoz, hogy a lenti kódokat ki is tudd próbálni rendelkezned kell egy friss és működő cakePHP telepítésre ahol már van egy felhasználód és a felhasználó beléptetésére az Auth komponenst használod. Ennek mikéntjéről olvashatsz a szakácskönyben vagy itt az előző bejegyzésben. Nem árt ha ismered a cake console-t mert egyrészt használjuk a példákban másrészt meg nagyon megkönnyíti a munkádat.

A probléma

… meghatározzuk a szabályrendszert ami eldönti, hogy melyik felhasználó mihez férhet hozzá …

Amint van egy webalkalmazásunk el kell döntenünk, hogy a különböző felhasználók mit csinálhatnak és mit nem. A példa kedvéért egy egyszerű webalkalmazást fogunk nézni, ahol a regisztrált felhasználók írhatnak bejegyzéseket és hozzászólhatnak egymás bejegyzéseihez.

A jogosultsági rendszer kidolgozásának első feladata mindig az, hogy meghatározzuk azt a szabályrendszert ami majd el fogja dönteni, hogy melyik felhasználó milyen jogosultsággal mihez férhet hozzá és mihez nem.

A következő jogosultságokat akarjuk beállítani:

  • Webalkalmazásunk regisztrációhoz kötött. A be nem regisztrált vendégek csak az oldal ‘Rólunk’ részét olvashatják el, illetve elérhetik a regisztrációhoz szükséges oldalt.
  • A regisztrált felhasználók írhatnak bejegyzéseket és hozzászólásokat, módosíthatják és törölhetik őket, illetve módosíthatják a saját felhasználói adataikat.
  • Az adminisztrátorok szintén írhatnak bejegyzéseket és hozzászólásokat a saját nevükben, valamint bármelyik felhasználó által létrehozott bejegyzést vagy hozzászólást szerkeszthetik vagy törölhetik. Más nevében nem írhatnak sem bejegyzést sem hozzászólást. Az adminisztrátorok feladata a felhasználók kezelése, teljes körűen hozzáférnek a felhasználók adataihoz.

A következő mintákban azt fogjuk megnézni, hogy ezt hogyan tudjuk megcsinálni a cake-kel, de nem fogunk minden egyes követelményt lekódolni. Remélem az itt megtalálható minták alapján már úgyis mindenkinek menni fog.

Általános elvként a fehér listás hozzáférés kezelést alkalmazzuk, azaz minden tilos ami kifejezetten nem engedélyezett, azaz alapértelmezés szerint senki nem tud semmit sem csinálni, a jogok pedig az engedélyeket tartalmazzák.

A CakePHP módszerei a jogosultságok kezelésére

A CakePHP a következő eszközöket adja a kezünkbe amelyek használatával a userek hozzáféréseit tudjuk szabályozni:

  • Vezérlőben beállított engedélyek
  • Modellben beállított engedélyek
  • Tevékenységek (actions) engedélyek
  • CRUD engedélyek
  • Objektum (object) engedélyek

A tevékenység engedélyek megkövetelik az ACL használatát, a többieket használhatjuk ACL-lel és nélküle is. Így ha jól számolom akkor összesen 9 féle módszer használható az engedélyek kezelésére. Sőt az egyes módszerek kombinálhatók és bővíthetők hihetetlenül rugalmassá és első körben nehezen emészthetővé téve ezzel az egész történetet. Ebből fogjuk a leginkább használatosakat áttekinteni.

Első módszer: Hozzáférések a vezérlő engedélyek alapján

Ennél a módszernél a jogosultságokat az egyes vezérlőkben fogjuk ellenőrizni. A módszer használatához az Auth komponens authorize változójának controller-nek kell lennie. Ha az authorize értéke controller akkor a vezérlőben lennie kell egy isAuthorized metódusnak aminek logikai értékkel kell visszatérnie.

<?php
//app_controller.php
class AppController extends Controller {

	var $components = array('Auth');		//az Auth komponens betöltése az összes vezérlő számára
	var $helpers = array('Html', 'Form');
	
	function beforeFilter(){
		$this->Auth->authorize = 'controller';	//itt gondoskodunk az authorize beállításáról
		$this->Auth->allow('display');		//pages controller-hez nem kell hitelesítettnek lennie
	}
	
	function isAuthorized(){
		return false;		//azaz alapértelmezés szerint senki semmihez nem fér hozzá
	}
}
?>

A kód azt hiszem magától érthetődő. Betöltjük az Auth komponenst, beállítjuk a vezérlő engedélyek módot, engedélyezzük az oldalak elérését és az isAuthorized függvénnyel tiltunk mindenkinek mindenféle más hozzáférést.

Ezzel a rendszerünk egyenlőre túlbiztosított mivel senki nem tud benne semmit sem csinálni. Első körben azt fogjuk beállítani, hogy a felhasználók megtekinthessék illetve módosíthassák a saját felhasználó adataikat. Ehhez a users_controller.php fájlt kell átírnunk valami hasonlóra.

<?php
class UsersController extends AppController {

	var $name = 'Users';
	
	function beforeFilter(){
		parent::beforeFilter();		//meghívjuk a szülő, azaz az app_controller beforeFilter metódusát
		//auth komponensben használt mezőnevek ha az adattábláink nem követik a konvenciókat
		$this->Auth->fields = array(
			'username' => 'usernev',
			'password' => 'jelszo'
			);
		$this->Auth->allow('register');		//a register action-hoz nem kell hitelesítve lennie
	}

Eddig ott vagyunk, hogy beállítottuk, hogy a hitelesítéshez milyen mezőneveket használjon a komponens, illetve, hogy a UsersController::register() metódusának használatát lehetővé tettük a be nem jelentkezett felhasználók számára is.

A vezérlőben való jogosultság ellenőrzésére itt is az isAuthorized függvénnyel történik.

	function isAuthorized(){
		//az admin joggal rendelkezők mindent tudnak csinálni
		if($this->Auth->user('jog') == 9)
			return true;
		//minden hitelesített user láthajtja saját magát
		if($this->action == 'view' && $this->Auth->user('id') == $this->params['pass'][0])
			return true;
		//minden hitelesített user módosíthatja saját magát
		if($this->action == 'edit' && $this->Auth->user('id') == $this->params['pass'][0])
			return true;
		return false;
	}

	
	function login() {
	}

	function logout() {
		$this->redirect($this->Auth->logout());
	}
	
	function register(){
		//ide kerül a regisztrációhoz szükséges vezérlő kód
	}

//ide jön még sok sok más metódus
?>

Az isAuthorized függvény először azt vizsgálja, hogy a hitelesített user adatbázisban található jog mezőjének az értéke 9-e. Ha az igaz, akkor egy adminisztrátorról van szó, azaz mindenhez hozzá engedjük férni. Ha az alkalmazásunkban adatbázis szinten is létre akarunk hozni felhasználó csoportokat – ami nem feltétlenül szükséges amint itt azt láthatjuk – akkor persze itt a user tábla csoport_id mezőjét fogjuk vizsgálni.

Ha nem adminisztrátorról van szó, akkor azt vizsgáljuk meg, hogy az url-ben érkező user_id paraméter (azaz pl a /users/edit/17 esetében a 17) megegyezik-e a hitelesített felhasználó id-jével, azaz, hogy saját magán akarja-e a szóban forgó műveletet végrehajtani. Amennyiben igen egy true visszatérési értékkel megadjuk a hozzáférési jogot, amennyiben nem akkor nem adunk hozzáférési jogot.

Megjegyzés: ha egy felhasználó hozzáférését elutasítjuk akkor nem árt közölni vele. Beállíthatunk az app_controller.php fájlban egy általános hibaüzenetet, és akár vezérlőnként vagy tevékenységenként módosíthatjuk is a következők szerint:

$this->Auth->authError = "Bocsi, de ehhez jogilag kevés vagy!";

Az üzenetet a nézetekben (view) így jelenítjük meg:

if ($session->check('Message.auth')) {
	$session->flash('auth');
	}

Ezzel meg is vagyunk, nem fogjuk a többi kívánt jogosultságot beállítani, aki szeretné lásson neki maga.

Második módszer: Hozzáférések a modell engedélyek alapján

A második módszer igen hasonló az elsőhöz azzal a különbséggel, hogy az itt is szükséges isAuthorized metódust nem a vezérlőben hanem a modellben kell létrehoznunk.
Módosítanunk kell az AppController-t, hogy a megfelelő authorize eljárást használja.

<?php
//app_controller.php
class AppController extends Controller {

	var $components = array('Auth');		//az Auth komponens betöltése az összes vezérlő számára
	var $helpers = array('Html', 'Form');
	
	function beforeFilter(){
		$this->Auth->authorize = 'model';		//itt gondoskodunk az authorize beállításáról
		$this->Auth->allow('display');		//pages controller-hez nem kell hitelesítettnek lennie
	}	
}
?>

Szükségünk lesz még az AppModel-re is. Amint látni fogjuk ennél a módszernél a isAuthorized metódus kap három paramétert amit használni tudunk. A példában itt az egyszerűség kedvéért minden jogosultságot az app_model.php fájlban kezelünk le de az egyes modellekhez tartozó jogokat akár a megfelelő model fájlban is elvégezhetnénk ehelyett.

<?php
//app_model.php
class AppModel extends Model {
	function isAuthorized($user, $controller, $action){
		/*
		debug($user);
		Array(
			[User] => Array(
			[id] => 1
			[usernev] => admin
			[jog] => 9
			)
		)
		*/
		//debug($controller);		//Users
		//debug($action);		//index:read, register:register a default $actionMap alapján vagy amit beállítunk
		
		if($controller == 'Users'){
			if($this->id == $user['User']['id']){
				//minden hitelesített user megnézheti magát
				if($action == 'read')
					return true;
				//minden hitelesített user szerkesztheti magát
				if($action == 'update')
					return true;
			}
		}
		
		if($controller == 'Comments'){
			//minden hitelesített user megnézheti az összess commentet
			if($action == 'read')
				return true;
			$userId = $this->find('first', array(
									'conditions' => array('Comment.id' => $this->id),
									'fields' => 'user_id'
									));
			if($user['User']['id'] == $userId['Comment']['user_id']){
				//minden hitelesített user szerkesztheti a saját commentjeit
				if($action == 'update')
					return true;
			}			
		}

		//az admin jogú userek mindent tudnak csinálni
		if($user['User']['jog'] == 9)
			return true;

		return false;			//egyébiránt meg senkinek nincs joga semmihez
	}

}
?>

A kód itt is azt hiszem magáért beszél. Annyit fűznék hozzá, hogy a $action paraméter nem feltétlenül a meghívott tevékenység tényleges nevét fogja visszaadni amire jó odafigyelni.

Modell vagy Vezérlő alapú engedélyek?

Amint láttuk az első két módszer megvalósítása nagyban hasonlít egymásra. Mi dönti el, hogy melyiket használjuk? Ha inkább a fat model-eket kedveljük akkor a modellbe fogjuk tenni az ellenőrzést. Olyan esetekben amikor a hozzáférés feltétele nem egy adattól függ az adatbázisban hanem valami mástól, akkor inkább a vezérlőben van a helyük. Ilyen például, hogy egy licitáló oldalt mindenki elérhet délig, aztán délután 3-ig már csak azok a kik licitáltak, ezután pedig már csak a nyertes ajánlattevő.

1 hét múlva folyt köv.

2 thoughts on “Felhasználói jogosultságok kezelése – CakePHP 1. rész

  1. Pingback: Felhasználói jogosultságok kezelése - CakePHP 1. rész

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöljük.