I have implemented a simple role check code with the help of helpers using sessions in my codeigniter 3 application.
Access Helper: Defines a function named as access_right which checks if the logged in user has access right to visit a specific module or not and correspondingly returns true or false.
In addition to it, I also have two versions of navigation bars one for admin user and for non admin users.
In controller i have added following code to perform the check for both i.e. which navigation to load and if the logged in user has access or not to module:
if($this->session->userdata('user-type') === 'admin')
{
$this->load->view('templates/sub_header_admin');
}
else
{
$this->load->view('templates/sub_header');
}
if(access_right('client_information'))
{
$this->load->view('pages/clientview/client_page');
}
else
{
$this->load->view('templates/restricted_access');
}
$this->load->view('templates/footer');
Problem is I need to repeat this much of code in each and every method inside a controller.
access_right('client_information'), of-course instead of client_information i check for different value like 'operator_information' depending on which controller is loaded.
How can i avoid this repetition of code ?
Just like you avoided repeating code for checking 'client_information' access rights - create a function to do that.
Related
I am a newbie to PHP/Kohana application development.
In the web app i am developing , whenever a new request come to the controller i am required to check if the user is logged-in or is he having sufficient privileges to commit the action he requested. Since my application have different category of members(having different degree of authority), every controller method ends up having multitude of if/else branches. the code is repeated in other controller methods as well.
Is there any suggested way to centralize these calls and to avoid code repetition? I mean is the only way to achieve this by writing a method to encompass all the user session code ? or am i missing any functionality that is baked into the PHP/Kohana which is already dealing this scenario?
eg:-
if (Auth::instance()->logged_in('commentator')) {
// do something here.
}
else if (Auth:instance()->logged_in('admin')){
// do something here.
}
else if (Auth:instance()->logged_in('reviewer')){
// do something here.
}
Create a controller named Controller_Authenticated with some code like this:
protected $login_level;
public function before()
{
parent::before();
if (Auth::instance()->logged_in('commentator')) {
$this->login_level = 'commentator';
}
elseif (Auth:instance()->logged_in('admin')){
$this->login_level = 'admin';
}
elseif (Auth:instance()->logged_in('reviewer')){
$this->login_level = 'reviewer';
}
else {
// Redirect to login page here, or display a "you are not logged in" message
}
}
Then, have your other controllers extend Controller_Authenticated instead of just Controller. Then you can check the value of parent::$login_level to see what kind of user this is.
That way, all of your login-checking code is in one place, and checking what kind of user you are is done automatically when the controller loads (before the action is called).
The Kohana documentation has almost exactly this example for using a before method to handle login stuff.
If I want to create a simple mechanism such as the rights extension that serves limiting and checking the access rights to the action is that I have to do on each of my controller ie preFilter ?
For example in the case. I create a table with a set of user authentication in the table below :
1 = Allow and 0 = Not Allow
Every controller I have, if the user requests to the action it will always be checked whether the current user has permissions or not
I see here : http://www.yiiframework.com/doc/guide/1.1/en/basics.controller that this can be done
class PerformanceFilter extends CFilter
{
protected function preFilter($filterChain)
{
// logic being applied before the action is executed
return true; // false if the action should not be executed
}
protected function postFilter($filterChain)
{
// logic being applied after the action is executed
}
}
How do I order to be able to use it with the AR in Yii to be able to do this?
Or is there a better way for this case?
Does it help to not make the same code over and over again in every action to check the authorization of users that access is permitted or not
Thanks
I am currently building a web app which has two models, Donor and Donation Models respectively. It has multiple user roles. When the staff user first registers a donor, I want him to be redirected to another form which allows him to fill in the Donation details(the donor is registered once the first donation is successful).
Firs of all, should I create a donation controller, from which I would redirect the user using:
return $this->redirect(array('controller'=>'donations','action'=>'add'));
For the above to work, it requires me to save the newly registered donor's id in a session like so :
$this->Session->write('id', $this->Donor->id);
So the user is redirected to 'donations/add' in the url, and this works fine.. However I think this has some flaws. I was wandering whether I should create another action inside the Donor controller called 'add_donation', which will have its respective 'View'. The idea is to be able to form a url of the sort : 'donors/add_donation/4' (4 being the donor_id ! )
This URL follows this construct: 'controller/action/id'
If anyone could shed some light on best practices, or describe any caveats to my solution(the former, using session etc.) , please do help a brother out! Ill be deeply indebted to you! Thanks in advance!
After you saved the data you can do this in the DonorsController:
$this->redirect(array(
'controller' => 'donations',
'action' => 'add',
$this->Donor->getLastInsertId()
));
There is no need to return a redirect, it's useless because you get redirected. Notice that we pass the last inserted record id as get param in the redirect. The redirect method of the controller calls by default _stop() which calls exit().
CakePHP3: There is a discussion about changing that default behavior in 3.0. Looks like in CakePHP 3.0 the redirect() won't exit() by default any more.
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
I would not use the session here, specially not by saving it to a totally meaningless and generic value named "id". If at all I would use always meaningful names and namespaces, for example Donor.lastInsertId as session key.
It's not always clear where to put things if they're related but the rule of thumb goes that things should go into the domain they belong to, which is pretty clear in this case IMHO.
Edit:
Leaving this edit here just if someone else needs it - it does not comply with the usage scenario of the asker.
If you have the user logged in at this stage, modify the add function to check if the userId passed is the same as the one logged in:
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
if ($this->Auth->user('id') != $donorId) {
throw new InvalidArgumentException();
}
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
You can use also the same controller using more models with uses.
Or you can also to ask to another controller with Ajax and morover to get response with Json.
I saw some codes on internet which in order to check the permissions to access a concrete action, they use the Configure::read function in this way:
public function action1(){
if(!Configure::read('isAdmin')){
$this->redirect(array('controller' => 'depots', 'action' => 'status'));
}
//whatever
}
I was wondering, which is the difference between using Configure::read and Configure:write for this purpose and using $this->Session->read() and $this->Session->write()?
Which is a better way to check it?
Thanks.
Using the AuthComponent
If you make use of the built-in AuthComponent, CakePHP will store details of the currently logged-in user inside the session.
Getting properties of the currently logged-in User
Once logged in, you can access the information of the Used (e.g. role_id) via the AuthComponent. This can be done anywhere (also inside your Views or Models if desired);
For example;
if (123 === AuthComponent::user('role_id')) {
debug('hello admin user');
}
Or, inside a Controller:
if (123 === $this->Auth->user('role_id')) {
debug('hello admin user');
}
Accessing the logged in user
However, to dont have to repeat the group-id everywhere, it's best to creat a method for this (e.g inside your AppController);
/**
* Checks if the currently logged in user is an admin
*
* #return bool true if the current user is an admin
*/
protected function isAdmin()
{
// probably best to make the id configurable (Configure::write())?
return (123 === $this->Auth->user('role_id'));
}
Access control
To use a 'simple' authorisation, you can create your own isAuthorized() action in your Controller, which will allow you to block access to specific actions, based on the properties of the currently logged-in user;
Using ControllerAuthorize
I can't see why you would put the user role in the Configure array, as it is intended to contain application wide settings.
Personaly I have a table in my database that contain the roles. Although some roles may be added to it, there are some that I never modify (typically the administrator role).
This allows me to store its value as an application parameter in Configure and check for it later:
bootstrap.php
Configure :: write('administrator.role_id', 1);
TestController:
if($this->Auth->user('role_id') == Configure :: read('administrator.role_id'))
{
//do things specific to admin role
}
That said if the user role is stored dynamically in one way or another in Configure, it could probably work as well, but that's probably not the more elegant solution.
I would like to check, whether user's account is activated while loggin in, but cake's Auth component takes care of the login in a way I don't know how to control. Cake basically uses blank login function and I have no idea how to check value of User.active.
Thanks in advance
The AuthComponent has a property for setting additional conditions just like this, called $userScope.
Just include this line in your beforeFilter() Auth setup block:
$this->Auth->userScope = array('User.active' => true);
Note: the above applies to Cake 1.x. For 2.x use:
$this->Auth->scope = array('User.active' =>true);
Then you can leave your login method blank and the AuthComponent will append this extra condition when authenticating the visitor.
You can see all the additional properties here:
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#configuring-authentication-handlers
If you don't include this extra scope, then inactive users will still be able to log in and you'd have to log them out in your login() method after checking.
On your Users controller, or wherever you want to place it (the action that the login form links to):
function login() {
if ($this->Session->read('Auth.User')) {
$active = $this->Auth->user('active');
if ($active) {
//(do stuff)
}
else {
//(do other stuff)
}
}
}
This assumes that there is an "active" column in your User table that contains either true or false (or 1 or 0). $this->Auth->user() allows you to access the current logged in user's data. More information in here: http://book.cakephp.org/view/1264/user