cakephp common action for admin and member - cakephp

For my project I have three types of users. Admins, members and Others.
There are certain functions that both admin and members could perform.
I know how to do routing and check for admin, and calling admin methods. But am not sure how to share a function between user types.
Any hint?
Best,
R

You could simply do it using Auth component.
Uncomment Routing.prefixes = array('admin', 'manager'); in your app/Config/core.php file.
Setup an Auth component with the help of this link.
Now if your controller's method is common with two user roles 'admin' and 'manager', then it is simple to define a method for any role and invoke it in another method.
Lets say in your UsersController.php
public function admin_list()
{
/*.... define here ..... */
}
public function manager_list()
{
$this->admin_list();
}
This technique will also help you to manage if you want to show some other things with user list for the manager user role.

Use isAuthorized() from Auth component. Let's say that your users is in table users.
In your AppController.php put:
public function isAuthorized($user){
return true;
}
In your UsersController, lets say that you want method1 and method2 to be visible only for admins and members, not for others.
public function isAuthorized($user){
if(in_array($this->action, array('method1', 'method2'))){
if($user['role'] != 'admin' || $user['role'] != 'user'){
return false;
}
}
return true;
}
And, of course, include your AuthComponent in AppController:
public $components = array('Session', 'Auth');
If you have any further questions, feel free to ask. :)

Related

Granting and denying access to some views in cakePHP

Up to this point we have been granting and denying access to some views in the following way:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->deny('add','edit','index','view', 'delete', 'translate');
}
It worked perfectly, but now as requirements have changed, we need to do a conditional filter and give an appropriate message. It should take User's role, which can be get at $user['role'], and then depending on action it should grant/deny it with providing appropriate message.
Any help or guidance is much appreciated.
For example,
user's role are buyer & seller.
Seller can perform the following action add , update & delete & Buyers can perform the following action view, translate
public function beforeFilter() {
parent::beforeFilter();
if($user['role'] == 'buyers') {
$actions = array('view','translate');
} else {
$actions = array('add','update','delete');
}
$this->Auth->deny($actions);
}
For more details go to flowing link
That's it.
You can also look into ACL here is a short tutorial on ACL in cakephp
http://mark-story.com/posts/view/auth-and-acl-an-end-to-end-tutorial-pt-1

CakeDC admin is accessible by all kinds of users/roles by default, make it secure

I've installed CakeDC Users plugin and I found out that role, is_admin don't function by default. If I login with regular username role=registered and is_admin=0, I can still go to /admin/users/add/. Why are there two types of checks, role and is_admin, what if role=administrator and is_admin=0, or vice-versa?
I am looking for a preferred solution to this problem so I could secure admin section and make use of user roles on different pages. Still, can't understand why is_admin is present, when role=administrator could take care of it all.
I solved the very same issue by adding the following piece of code in "app/Controller/AppController.php" in method "beforeFilter()" :
if (isset($this->params['prefix']) && $this->params['prefix'] == 'admin') {
if ($this->Session->check('Auth.User.role') and 'admin' !== $this->Session->read('Auth.User.role')) {
$this->Auth->deny('*');
return $this->flash('Non admin access unauthorized', '/');
}
}
While I admit this solution is not optimal, it sure does the trick!
This is not an issue of the plugin: You have to implement your auth application wide on your own. The plugin just gives you the basics but does not your job of customizing the app based on the requirements of your client. I recommend you to read this chapter http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
The is_admin check AND role field are there for multiple reasons: Your user can have any role but only if they have is_admin checked they can access an admin area for example. is_admin alone does not allow you to have roles. Both fields are there to cover different scenarios. Again, the plugin is thought to be a kick start and base you can build on. That's what you have to do when you want to customize it.
There is an example that shows pretty much how to use whatever you need:
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#using-controllerauthorize
class AppController extends Controller {
public $components = array(
'Auth' => array('authorize' => 'Controller'),
);
public function isAuthorized($user = null) {
// Any registered user can access public functions
if (empty($this->request->params['admin'])) {
return true;
}
// Only admins can access admin functions
if (isset($this->request->params['admin'])) {
return (bool)($user['role'] === 'admin');
}
// Default deny
return false;
}
}

How do I blend the functions of isAuthorized and Auth->allow/deny into one method in CakePHP?

In my design, an action has a rank, 0-10 required to access it (0 being a guest [not logged in], 10 being an admin). Each user has a rank, 0-10. If you have the rank or higher, you can access the action, otherwise you can't. Nice and simple, it's all I need.
The problem is that CakePHP wants me to treat actions with two separate concepts. I have to mark them Auth->allow/deny to determine if the auth system even bothers with them, and then I control access to them with isAuthorized().
isAuthorized works great for my needs... except that any action I want to have access of rank 0 to has to be Auth->allow()... which then ignores my isAuthorized method completely. If I deny all the pages, the login triggers on the pages that should be rank 0, before it checks isAuthorized, so even if I grant authorization through it, the person has to log in first.
Is there any way to merge the two systems together, or a simple way to replace it? Most of the auth system is great, and takes care of business for me without me having to mess with it... but this is just awkward and is going to cause problems when I don't notice a mixed up allow/deny or something.
Thanks!
As far as I see it, the only way to do this is to create a guest user. This is because the Auth component checks the existence of a user before ever getting to isAuthorized() like you explained.
You can do this by writing directly to the session. This will tell the Auth component that someone is logged in, so your isAuthorized() method will be called.
AppController
public function beforeFilter() {
// if no one is logged in, log in a guest
if (!$this->Auth->user()) {
$this->Session->write(AuthComponent::$sessionKey, array(
'User' => array(
'id' => 0
)
));
}
}
public function isAuthorized($user) {
$authorized = false;
if ($this->Auth->user('id') == 0) {
// public guest user access
}
// other logic
return $authorized;
}
A possibly better way to do this is to use a custom authentication object, which basically tells Cake to use that class to help authenticate. This splits the logic into a separate class, making it easier to test and even disable.
app/Controller/Component/Auth/GuestAuthenticate.php
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
class GuestAuthenticate extends BaseAuthenticate {
public function authenticate(CakeRequest $request, CakeResponse $response) {
// no real authentication logic, just return a guest user
return array('User' => array('id' => 0));
}
}
AppController
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form',
'Guest' // tell Cake to try Form authentication then Guest authentication
)
)
);
public function beforeFilter() {
if (!$this->Auth->user()) {
// no user? log in a guest (this will fail form authentication
// then try guest authentication)
$this->Auth->login();
}
}
public function isAuthorized($user) {
$authorized = false;
if ($this->Auth->user('id') == 0) {
// public guest user access
}
// other logic
return $authorized;
}
You can find more information on custom authentication objects here: http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
Maybe this has already been dealt with satisfactorily but I have a solution.
In my AppController I have the following:
public function isAuthorized($user = null) {
if (in_array($this->action, $this->Auth->allowedActions)) {
return true;
}
return false;
}
As you've found, if you don't explicitly authorize actions, they are denied to authenticated users, even if they are allowed to the public. This snippet of code just makes the isAuthorized() method honour the settings in the Auth->allow() list.
It seems to work for me, so I hope it helps.

CakePHP - Create an Offline/Online feature for a site

======================================== EDIT ====================================
Per charles suggestion, I accomplished the Offline/Online feature using the following code, based on Charles code:
<?php
Class AppController extends Controller{
// prevents unauthorized access
public $components = array('Auth');
// the name of the model storing site_offline boolean
public $uses = array('Configuration');
// callback invoked before every controller action
public function beforeFilter() {
// returns your site_offline status assuming 0 is offline
if ($this->Configuration->get_site_status() == 1) {
$this->Auth->allow('*');
}else {
if(($this->Configuration->get_site_status() == 0) and (!$this->Auth->user() == null)){
// I set it up like this for now to allow access to any authenticated user,
//but later will change it to only allow admins access thru a login form
$this->Auth->allow('*');
}else{
//If site is offline and user is not authenticated, sent them to
// the a screen using the OFFLINE layout and provide a screen for login.
$this->layout = 'offline';
$this->setFlash('Maintenance Mode. Check back shortly.');
$this->Auth->deny('*');
}
}
}
}
?>
Then I used jQuery to hide my login form. An admin clicks on the message to show the login form. This is an attempt to prevent any login tryouts.
============================ END EDIT ==========================================
I would like to know what is the best way to create a "site offline/online" feature in CakePHP. Basically, I would like to allow an administrator to turn off access to the site to everyone registered or not. The offline page should have a login access thru which only admins can login.
The idea I have is to create some kind of dashboard controller, where as soon as the administrator is logged in he/she will be redirected to this dashboard from where he can access the other controller actions (admin_edit, etc). This dashboard and all admin actions (admin_delete, etc) should use the admin layout.
Is this a good approach? For the offline/online feature should I create a settings table with a site_offline field that can be turned on or off? Where in app_controller and what code should I use to check for it before allowing or not access to the site?
Thanks a lot for your help,
first add a config in the core.config
/*
* This is the site maintenance
* The built in defaults are:
*
* - '1' - Site works
* - '0' - site down for maintenance.
*/
Configure::write('Site.status', 1);
in the AppController you'll check it in the beforeRender function
if (Configure::read('Site.status') == 0) {
$this->layout = 'maintenance';
$this->set('title_for_layout', __('Site_down_for_maintenance_title'));
} else {
// do something
}
i'm here load a separate layout form the maintenance to let me add whatever layout i want
If you were going to save site_offline boolean value in a database table you should be able to easily do this with a callback in AppController and the Auth component.
<?php
AppController extends Object {
// prevents unauthorized access
public $components = array('Auth');
// the name of the model storing site_offline boolean
public $uses = array('NameOfModel');
// callback invoked before every controller action
public function beforeFilter() {
// returns your site_offline status assuming 0 is offline
if ($this->NameOfModel->get_status() === 0) {
$this->Auth->deny('*');
} else {
$this->Auth->allow('*');
}
}
}
I've always liked the idea of the DashboardsController for admin functions. That's actually the exact name of the class I use and the same general idea.

Roles in CakePHP Auth Component

I'm trying to use roles in the CakePHP Auth component. The roles would be user, admin, super-admin, etc. I'm having difficulty with placing a conditional in each controller based off the user role. I tried the following and it didn't work:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
if($this->Auth->user('roles') == 'admin') {
$this->Auth->allow('index', 'add', 'edit', 'delete');
}
elseif($this->Auth->user('roles') == 'super-admin') {
$this->Auth->allow('index', 'add', 'edit', 'delete', 'make_super_admin', 'privileges'); //Note difference in superadmin priviledges
}
The problem is with the conditional. I want the function to go in each controller (UsersController, PatientsController, AdmissionsController, etc.) and based off the user role, give different permissions.
Placing this logic in the beforeFilter() of the AppController class should do the trick.
Another thought that I had was that maybe you should consider using the Acl component in conjunction with the Auth component. The Acl component will give you out-of-the-box granular control over every action in every controller. If used correctly, you'd only have to set permissions on the actions for each role and the type of access-control checking that you are currently trying to do will be automated.
The book has an excellent tutorial on how to make this work. I'm using it in my application and it's well worth the time invested to setup and understand how it all works. Reference below.
CakePHP Book :: Simple Acl controlled Application
I don't know if this is your problem, but if you want to allow every action you have to use * instead of nothing:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
if($this->Auth->user('roles') == 'admin') {
$this->Auth->allow('*');
} elseif($this->Auth->user('roles') == 'super-admin') {
$this->Auth->allow('*');
}
}
If you want to set those permissions for every controller it would be the best to put it in your AppController so it will affect everything.

Resources