I am building a public facing web/mobile application that will have a substantial admin controlled back end. Although this question is quite general, I am using CakePHP to build the application.
I am looking into whether it would be wise to split the admin and public applications into two applications. Both applications would use the same database. The main reason I am looking into this would be for improved security, but also portability of the front end.
I have also thought about developing a CakePHP based RESTful API that both the front and back end would share.
Would an API be the best way to go about this or should each application simply only share the database, or is splitting the applications just creating more work in the long run?
I think it's best to keep both the Admin functionality and REST API in your main CakePHP application. (You don't specify a version, but I'm assuming since you're making a new app you're using 2.0. It has some benefits below.)
As mark mentioned you can do something called prefix routing that allows you to create special actions that only admins can use in your existing controllers. There's a full explanation in the Prefix Routing docs.
The gist is that you specify the prefix you want in core.php:
Configure::write('Routing.prefixes', array('admin'));
So going to /admin/users/edit/5 would call the method admin_edit of our UsersController passing 5 as the first parameter. The view file used would be /views/users/admin_edit.ctp.
You can set a default "admin" homepage in routes.php:
Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true));
As for the REST API, if you're using 2.0 this is a built-in that is pretty easy to turn on. There's a good intro on the REST page.
Activating it just requires adding these lines to routes.php:
Router::mapResources('recipes');
Router::parseExtensions();
This sets up some default REST routes:
#HTTP format URL.format Controller action invoked
GET /recipes.format RecipesController::index()
GET /recipes/123.format RecipesController::view(123)
POST /recipes.format RecipesController::add()
PUT /recipes/123.format RecipesController::edit(123)
DELETE /recipes/123.format RecipesController::delete(123)
POST /recipes/123.format RecipesController::edit(123)
There's more info in the doc so please check it out.
I don't think it makes sense to split the application into two separate ones.
it can easily be accomplished that user frontend and admin backend are separated completly using an "admin" prefix.
So all user actions
/
/controller/
/controller/action
etc
all admin actions
/admin/
/admin/controller/
/admin/controller/action
and so on
Related
I have read numerous times here and on various websites that the ACL Component is a very powerful tool. Yet the next sentence usually begins with a version of "However, the cake manual poorly documents this and so this is the system that I am using instead." I am a programming novice and have definitely struggled with learning Cake because of the docs as well; I am at a loss as to what exactly makes the AclComponent so strong, since everyone recommends it but many are still using something else. Can anyone suggest specific examples or tutorials that will help me understand this component better? For example, what kinds of code it helps me avoid having to write, how to limit access by each user instead of the entire group, etc?
Cake's ACL system is powerful because it's extremely flexible and allows very fine grained control over the access to your application. Most people use it in a basic sort of way, i.e., this user/group has access to this controller method. While this is the common use case, you can also use it to say, limit a model's access to another model's create action.
For example, to limit an Admin group to only creating records for a PrivateModel model:
// add aco
$this->Acl->Aco->add(array(
'alias' => 'PrivateModel'
'model' => 'PrivateModel',
'foreign_key' => null
));
// add aro
$this->Acl->Aro->array(array(
'alias' => 'Admin'
'model' => 'Group',
'foreign_key' => 1
));
// allow Admin to read PrivateModel #1
$this->Acl->allow('Admin', 'PrivateModel1', 'create');
// check permission
$allowed = $this->Acl->check('Admin', 'PrivateModel', 'read'); // true
$allowed = $this->Acl->check('Admin', 'PrivateModel', 'create'); // false
The default answer to "should I use ACL" is often "no" simply because it can take some time to set up and understand. Cake's ACL examples were enough to get me going on it when I originally had no understanding of even the ACL concepts or MPTT trees.
Currently I have an app that has groups as AROs, and the ACLComponent uses the controller to check an isAuthorized() method which pulls the group from the logged in user and uses it to check see if the action is authorized. Again, this is probably the most basic approach to ACL.
As you have already pointed out in your question "However ... cake documentation", I couldn't agree more.
I have seen many of my team members in past struggle to grab the concept of whole Acl, Aro and Aco, and cake's documentation may be adds additional complexity to it than solving it.
The real magic of ACL begins with Aro and Aco.
ARO (Access Request Object) - They are the entities who request for services.
for eg. Users, Roles (Admin, Manager, Moderator)
ACO (Access Control Object) - They are the entities which are requested.
for eg. Posts, Posts->add, Posts->view, Posts->edit
We can configure our models with requester behavior such that everytime new record is created, it gets automatically synced with corresponding Aro.
As already demonstrated by jeremyharris, you can use Aro and Aco mapping with corresponding privilages to limit/control the access control of your application.
Also, you can make your life pretty easy with ACL by using a plugin Alaxos ACL This plugin really simplifies the whole ACL setup, especially from UI perspective
The cake console also provides a shell to initialize your db for ACL setup
cake acl initdb // cakephp 1.1, from shell with create db setup for acl
$ cake schema create DbAcl // cakephp 1.2 and above
There is an additional plugin from Markstory called AclExtras, it provides you a shell to make acl management more easy like creating aco nodes, testing and recovering aco, aro trees. It's an amazing plugin.
All,
I have a CakePHP app I am developing with user accounts and some social interaction and I am looking to allow each user to have a profile and make it public and whatever information the user decides to make available. Currently the user is able to access his/her personal account at http://www.domain.com/account, but I want the user to also have a profile at http://www.domain.com/users/profile/user234.
What is the best approach?
Create a function profile($username) in my users_controller.php?
Create a profiles_controller.php to handle users profiles?
Is there a better way?
Or is there a CakePHP Profile Plugin available I can use
Also,
Is it possible to use CakePHP routes to have something like this: http://user1234.domain.com?
Thank you for you help!
1 & 2) Both ways work. I would put it profiles controller because its simply more logical but there is not real guideline for that. Usually you do things in the domain they belong to.
3) Not really.
4) Not for profiles but for the whole user thing http://github.com/cakedc/users But be aware that the profiles part is using a key/value storage for the fields of the profile. But you can simply change that by extending the plugins models and controllers on app level - OOP 4tw! :)
For subdomain routing you need to implement a custom route object. See this ticket related to that topic. http://cakephp.lighthouseapp.com/projects/42648/tickets/2429 Lookup the book.cakephp.org if you need to learn how to create custom routes. See http://book.cakephp.org/2.0/en/development/routing.html?highlight=router#custom-route-classes for CakePHP 2.0. And see http://book.cakephp.org/1.3/en/view/1634/Custom-Route-classes for 1.3.
This is what I need to do:
I'm creating a site in CakePHP where I need to show different stuff (logo, pictures, etc) depending on what sub-domain the user has used to get to my site. For example: let's say there are 3 sub-domains:
subdomain1.mydomain.com
subdomain2.mydomain.com
subdomain3.mydomain.com
All three sub-domains will point to the same folder in the server where my CakePHP app is. I would like to know how can I get the sub-domain used by the user so I can show different things depending on that.
I don't know if this can affect my question, but there's one more thing. The users won't actually use the sub-domain links. They will use other domains that redirect to the sud-domains. For example, a user will enter www.whateverdomain1.com and he will be redirected to subdomain1.mydomain.com. However, I've been told that the user won't actually see the redirection, he will always see the www.whateversomain1.com that he used.
Any ideas? Thanks so much in advance!
The easiest way I can think would be to have your webserver redirect requests from sub.domain.com to domain.com/sub, and from there using the route configuration.
In the route configuration - you have two options, either to use prefixes (http://book.cakephp.org/view/945/Routes-Configuration#Prefix-Routing-950) or setting up named parameters:
Router::connect(':subdomain/:controller/:action/:id', array('id' => '[0-9]+'));
And in your controllers you can then check via
$this->params
to see what the subdomain is and set your variables accordingly.
I went through the tutorials and examples on the CakePHP Acl and Auth components today in detail. I configured my Auth component to use $this->Auth->authorize = 'actions'. With this I was able to successfully restrict access to specific site actions without a problem.
However, my application needs to go a bit beyond this and I'm unsure of how best to accomplish my goals for this application.
Within the application that I am developing using CakePHP 1.3.8, there are specific "site features". For example, users of the application will have the ability to message one another.
I want to treat each message as an ACO so that I can control who can and cannot view or delete the message.
Another site feature is the earning of "badges" for achieving certain goals. For these badges I'd like to treat them as ACO's for the locking and unlocking of these badges.
I do not think that I can do this with the out-of-the-box ACL functionality of CakePHP as this goes beyond restricting access to actions. I'm looking for any ideas on how best to achieve this functionality.
With the standard ACL functionality in CakePHP it's only possible to create ACO entries for controller actions. This means that your setup (treating every single message as a seperate ACO) will not fly. Same as with badges.
For your messages I would go for a setup in which you would check in your view/edit/delete methods if a certain user is the sender or receiver of the message.
Something like
# in messages_controller
function view($id) {
if(!$isSender($loggedInUserId) || !$isReceiver($loggedInUserId)) {
$this->Session->setFlash("You're not allowed to view this message")
$this->redirect('index');
}
# do view stuff here
}
function edit($id) {
if(!$isSender($loggedInUserId)) {
$this->Session->setFlash("You're not allowed to edit this message")
$this->redirect('index');
}
# do edit stuff here
}
Regarding the badges, I would go for a regular HABTM (HasAndBelongsToMany) relation between a User and a Badge. When a User reaches a certain goal, you make a call like Badge::unlock($badge, $user) which saves the new badge for the user to the users_badges join table.
From there you can do basic stuff like listing all the badges for a certain user, etc.
I studied over Cake's Acl component much closer and figured that I could write something that sort of imitates this functionality for my internal "feature" access control. My thoughts are that I could have a Faro (Feature access request objects), Faco, and Facos_Faros table. Faco and Faro will have a HABTM relationship. I could then create my own component that manages it all.
I am trying to create a basecamp like login where users can login to see their companies projects using the url:
http://abc.com/companyname/
I dont know how to create a 2 level auth... (one at the company level and another at the user level)
I am new to cakePHP and I dont know how to modify the in built Auth component for my requirement.. Any help would be grateful...
I would use the Auth component for the login. I wouldn't mess with the ACL and stuff as that's pretty confusing I find.
I would approach this by adding a user_level, access_level, or permissions column in your users table. Then in here you can store a numerical value or similar.
Then in the User model, when they login using Auth you can store that value in the Auth user session object. So you can get at it using $this->Auth('User.access_level') in your controllers.
Now the Auth component by default has an isAuthorized() function in the app_controller. This function is called to see if someone has logged in. You can modify this to check that access_level and take action appropriately. I used this technique so that users can't get into the /cms routing unless they are admin = 1.
There is more information on this in the docs, http://book.cakephp.org/view/172/Authentication and you can find out more about isAuthorized() here, http://api.cakephp.org/class/auth-component#method-AuthComponentisAuthorized
Do make sure that you setup all your Auth component variables in your app_controller. Also make sure that your auth type is set to controller, and that you're allow() and deny() are configured properly.
The one big catch with all this, is that if you using a beforeFilter() in your controllers, you will need to make sure to do parent::beforeFilter() to ensure that the stuff in the app_controller is run beforehand :)
Honestly, I think that you should check out the ACL component. The book tutorial is very good if you follow it through. The major caveat is that it does not provide a mechanism for row-level access control (e.g. can user X edit this particular entry). However, it does provide a basis for doing user/group level access control, which you can then extend yourself to create the row level access you require.
In short, the ACL component supports cascading permissions (e.g. subgroups can have finely-grained access control, but otherwise inherit permissions from the parent group). That can make life a lot easier, if you need both robustness as well as granularity.
You might also check out the bakery, as there are additional auth components written by the community that may serve what you need. Highly recommended, as Auth/ACL stuff is difficult to do well, and always a major concern with web apps.