Λοιπόν, πρόκεται να παρακάμψουμε το προεγκατεστημενο σύστημα ελέγχου πρόσβασης του Yii και να το αντικαταστήσουμε με ένα δικό μας. Για να το κάνουμε αυτό πρέπει να καταλάβουμε πρώτα κάποια βασικά πράγματα σχετικά με το πως λειτουργούν κάποια πράγματα στις εφαρμογές του Yii.
Εισαγωγή στα φίλτρα - Φίλτρα κλάσης: Και καταρχήν τα φίλτρα. Ένα φίλτρο μπορεί να είναι μια μέθοδος ή μια κλάση. Θα αναφερθώ και στις δύο περιπτώσεις γιατί ενώ εμείς θα χρησιμοποιήσουμε την δεύτερη, οι εφαρμογές του Yii χρησιμοποιούν εξ’ορισμού…και τις δύο! Ας ξεκινήσουμε από την περίπτωση της κλάσης. Στην περίπτωση αυτή ένα φίλτρο δεν είναι παρά μια κλάση η οποία επεκτείνει την κλάση CFilter. Η κλάση CFilter έχει (μεταξύ άλλων) δύο μεθόδους. Την preFilter() και την postFilter().
class CFilter extends CComponent implements IFilter
{
...
protected function preFilter($filterChain)
{
return true;
}
protected function postFilter($filterChain)
{
}
...
}
Όταν προσθέσουμε ένα φίλτρο σε έναν Controller, τότε πριν την εκτέλεση ενός action (της αντίστοιχης μεθόδου δηλαδή) του Controller εκτελείται η μέθοδος preFilter και μετά την εκτέλεση του action εκτελείται η postFilter(). Αν η preFilter() επιστρέψει true τότε η εκτέλεση του action προχωρά κανονικά. Αν επιστρέψει false η εκτέλεση του action διακόπτεται. Η postFilter() τυπικά δεν επιστρέφει κάτι μιας και το action έχει ήδη εκτελεστεί πριν από αυτή και άρα δεν μπορεί να το διακόψει. Στα φίλτρα που ορίζουμε απλά κάνουμε override τις δύο αυτές μεθόδους. Στην περίπτωσή μας, όπου θέλουμε να ελέγξουμε την πρόσβαση, θα ασχοληθούμε μόνο με την preFilter().
Φίλτρα μεθόδου: Μπορούμε να ορίσουμε και το φίλτρο σαν μια μέθοδο του Controller. Στην περίπτωση αυτή, αν το φίλτρο μας ονομάζεται π.χ CheckCredentials , η μέθοδος που υλοποιεί το φίλτρο θα πρέπει να ονομάζεται filterCheckCredentials($filterChain). Αν το φίλτρο αποφάσιζε ότι το action πρέπει να εκτελεστεί τότε θα πρέπει μέσα από τη μέθοδο να εκτελεστεί η εντολή:
$filterChain->run()
Όπως υποψιάζεσται ο κώδικας της μεθόδου πριν την παραπάνω εντολή αποτελεί το αντίστοιχο της μεθόδου preFilter() και ο κώδικας της μεθόδου μετά την εντολή αυτή αποτελεί το αντίστοιχο της μεθόδου postFilter().
Το φίλτρο ‘accessControl’ του Yii : Εξ’ορισμού οι εφαρμογές του Yii χρησιμοποιούν ένα φίλτρο ονόματι accessControl για τον έλεγχο πρόσβασης. Το φίλτρο αυτό καλείται μέσω μιας μεθόδου με όνομα filterAccessControl(), η οποία είναι ορισμένη στην κλάση CController. Στην πράξη όμως η μέθοδος αυτή είναι ένα περιτύλιγμα που φορτώνει ένα αντικείμενο κλάσης CAccessControlFilter.
public function filterAccessControl($filterChain)
{
$filter=new CAccessControlFilter;
$filter->setRules($this->accessRules());
$filter->filter($filterChain);
}
Η κλάση αυτή είναι ένα φίλτρο (επέκταση της CFilter με υπέρβαση των μεθόδων preFilter() και postFilter() ). Όπως βλέπετε από τον κώδικα της μεθόδου δημιουργείται ένα τέτοιο αντικείμενο, φορτώνονται οι κανόνες πρόσβασης που έχουμε ορίσει στην μέθοδο accessRules() του Controller και στην συνέχεια εκτελείται το φίλτρο.
Τοποθετώντας φίλτρα σε έναν Controller: Πως τοποθετούμε ένα φίλτρο σε έναν Controller? Με υπέρβαση της μεθόδου filters()! Φίλτρα μεθόδων και κλάσεων ορίζονται και ρυθμίζονται με τον ίδιο τρόπο με μια μικρή διαφορά στον τρόπο αναφοράς του ονοματός τους. Η προσθήκη του φίλτρου accessControl() και γενικά των φίλτρων μεθόδου γίνεται ως εξής:
public function filters()
{
return array(
'accessControl',
);
}
Μπορούμε να ορίσουμε ότι ένα φίλτρο θέλουμε να εκτελείται σε συγκεκριμένα μόνο actions. Αυτό γίνεται με χρήση των τελεστών ‘+’ και ‘-’ οι οποίοι προσθέτουν, ή εξαιρούν αντίστοιχα, το φίλτρο σε ορισμένα actions:
public function filters()
{
return array(
'myfilter - login',
'myfilter2 + edit,create',
);
}
Για τα φίλτρα κλάσης ο τρόπος διαφέρει λίγο. Δείτε τη διαφορά παρακάτω:
public function filters()
{
return array(
'postOnly + edit, create',
array(
'application.filters.PerformanceFilter - edit, create',
'unit'=>'second',
'amount'=>42,
),
);
}
Φορτώνουμε στον Controller ένα φίλτρο ονόματι PerformanceFilter του οποίου η κλάση βρίσκεται στον φάκελο “\protected\filters\” , ορίζουμε ότι το φίλτρο θα εκτελείται για όλα τα actions εκτός των edit και create και τοποθετούμε δύο properties στο φίλτρο (ένα με όνομα ‘unit’ και τιμή ‘second’ και ένα με όνομα ‘amount’ και τιμή ‘42’).
Τα φίλτρα εκτελούνται με την σειρά που ορίζονται στην μέθοδο filters() του Controller.
Ορίζοντας ένα νέο φίλτρο ελέγχου πρόσβασης: Ας ορίσουμε λοιπόν ένα φίλτρο με όνομα AuthorizationFilter. O βασικός του κώδικας θα είναι ο εξής:
<?php
class AuthorizationFilter extends CFilter {
protected function preFilter($filterChain){
}
protected function postFilter($filterChain){
return true;
}
}
Η κλάση αυτή θα αποθηκευτεί σε ένα αρχείο AuthorizationFilter.php και θα τοποθετηθεί στον φάκελο "\protected\filters\". Το επόμενο βήμα είναι να αφαιρέσουμε από όλους τους Controller των οποίων θέλουμε να ελέγξουμε την πρόσβαση το φίλτρο accessControl και να τοποθετήσουμε το δικό μας φίλτρο.
public function filters()
{
return array(
array(
'application.filters.AuthorizationFilter',
),
);
}
Η μέθοδος accessRules() είναι άχρηστη ποια και μπορεί να διαγραφεί!
Ας δούμε τώρα ένα παράδειγμα κώδικα που μπορούμε να χρησιμοποιήσουμε για τον έλεγχο πρόσβασης.
protected function preFilter($filterChain){
$issLogged = (!Yii:app()->user->isGuest);
$userAction = Yii::app()->Controller->getAction()->id;
switch($userAction) {
case 'index' : return true; break;
case 'create' : if ($isLogged) return true;
Yii::app()->Controller->redirect(Yii::app()->user->loginUrl);
break;
}
Yii::app()->Controller->redirect(Yii::app()->user->illegalActionURL);
return false;
}
Ο κώδικας αυτός καταρχάς ελέγχει αν ο χρήστης είναι συνδεδεμένος και ποιά ενέργεια προσπαθεί να εκτελέσει. Κατόπιν, ανάλογα με το αν έχει δικαίωμα ή όχι μπορούμε να επιτρέψουμε την ενέργεια ή να φορτώσουμε κάποια άλλη σελίδα (π.χ ανακατεύθυνση στη σελίδα του login αν δεν είναι συνδεδεμένος ή ανακατεύθυνση σε μια προειδοποιητική σελίδα αν είναι συνδεδεμένος και δεν έχει δικαίωμα πρόσβασης).
Υ.Γ: Ελπίζω να δουλεύει γιατί το έγραψα λίγο βιαστηκα!