I have for example table in database:
News:
id | user_id | title | body
and CRUD:
public function executeIndex(sfWebRequest $request)
public function executeNew(sfWebRequest $request)
public function executeShow(sfWebRequest $request)
public function executeCreate(sfWebRequest $request)
public function executeEdit(sfWebRequest $request)
public function executeUpdate(sfWebRequest $request)
public function executeDelete(sfWebRequest $request)
protected function processForm(sfWebRequest $request, sfForm $form)
How is the best method for secure this? I would like that USER can Edit, Update and Delete only own News. I can make this - get current ID user and compare with user_id from News and next redirect. Maybe i can make this with preExecute or in yaml file?
I used to do such a thing.
I choose to extend User class (myUser.class.php
in application lib directory) with method can($what, Doctrine_Record $with)
, also declared few types of update types, like: const UPDATE = 'update';
and others, in the same way.
After that in preExecute()
I've retrieved the currently requested object, in your case - News object, and calling if (!$this->getUser()->can(myUser::UPDATE, $news)) { /* redirect or whatever */ }
.
As you can see, it's very easy readable and maintanable.
This way you have all access logic in one, method - can()
, where you can specify any logic you need.
Hope, that helps you.
For your example, can()
method would be something like:
switch(get_class($with))
{
case 'News':
if ($with->getUserId() != $this->getProfile()->getId()) // Assuming that getProfile() gives me a User class which News record is referenced
{
switch ($what)
{
case self::UPDATE:
return false;
case self::DELETE:
return false;
}
}
else
{
return true; // The user is owner - he can do whatever he want.
}
break;
default:
return false; // or true, don't know what you need
}
I did much the same. But I am not extending the sfUser class. I used the filter chain http://www.symfony-project.org/book/1_2/06-Inside-the-Controller-Layer#chapter_06_filters of symfony and wrote my own SecurityFilter which was able to parse the route configuration.
I added an option to the specific route of my routing.yml
contact_list:
url: /contacts/:usergroup
param: { module: contacts, action: index }
options: { securityManager: UsergroupListSecurityManager }
for example: The securityFilter now uses an instance of UsergroupListSecurityManager to find out whether it is allowed to display the page.
So I was able to set a default "securityManager" and define any specific "securityManagers" on specific routes - I also was able to reuse some "securityManager" on different routes and in other contexts (creating contextmenu or toolbar).