I have a class called User with static function loginRequired(), which returns false if the user is logged in and true if the user is logged out. It also appends an error to an error class that I created that tells the person using the site that they must be logged in to view the content.
The idea is that for the top of each function that would require the user to be logged in, we write this code:
if(User::loginRequired()) return;
Which will output the error and immediately return from the function. I would rather do this, however:
User::loginRequired();
And return from the calling function inside of the loginRequired function... but because loginRequired() is in a separate class in a separate file, this won't work. Is it possible to return from the function that calls loginRequired(), within loginRequired()?
Thanks.
I'm not sure you can do exactly what you want, however, you might want to look at using exceptions. This would allow you to throw an exception in the User::loginRequired function and catch it at some higher level. You could also look at using the exit() PHP function.
The way I've seen a number of open source apps handle this is by having a require_login() function which performs a redirect should the user not be logged in.
Is the content WITHIN the actual page dynamic? What I mean is, do I need to authenticate just to see anything other than the login page, or do I see some things when I'm logged in and other things when I'm not, etc? Because if the entire directory/section of the server is behind a log-in screen you could just add something to the .htaccess file of the directory that redirects anyone not logged in, etc.
On the other hand, you could have that file holding the login status included into whatever page/script that the user is viewing, with the included file returning just the login status instead of its entire contents. This is covered under includes under Example 5, "include() and the return() statement". If you did this, you could use a ternary condition like:
$logged_in = (include('userlogin.php') == TRUE) ? TRUE : FALSE;
And then in each protected function have something like:
global $logged_in;
You are still stuck with an IF clause wrapping the entire function, but at least you have the login status. If you wanted to get rid of the IF inside of the function, you could always make calling the function conditional. Like:
$content = ($logged_in == TRUE) ? some_function() : redirect_User();
Then again, I just started learning this stuff 2 months ago and still don't understand classes and objects, so I could be way off base.
OT: I would consider changing the method's name to isLoggedIn() if your described purpose is the only one. A method called loginRequired() would be better off protecting confidential content.
Related
Background:
Inside large controllers I will have a number of different functions being called, to create a user, to update their order, to schedule in an event. Each of these operations are handled by a function in the model layer... here is an example of one of those functions:
$user_id = 1;
$data = array('name' => 'Billy');
if (updateUser($user_id, $data) === false) {
// handle error?
}
// continue with rest of controller
Problem:
I finally took a reality check today and realised that I have no good reason for coding like this...
If updateUser() returns false then something has seriously gone wrong with my Database Abstraction Layer that has prevented me from updating data in my database. This should never happen and therefore there are no practical errors to show my users anyway (that would allow them to take appropriate actions).
Basically my app is fundamentally broken at that point.
Question:
Should I bother to check functions that should never return false? If so how? Or should I just call them like this without any checks?
updateUser($foo)
createBooking($bar)
scheduleEvent($qux)
When something happens inside a function that should never happen, throw an exception.
And then you can handle (catch) all exceptions where you want to do that. For example by showing a friendly message to the user and logging all details for yourself so that you know what went wrong and where.
Then you can get rid of the if statements and only use these when there are valid / normal options.
To check If a user is logged in I need to pull off a pretty long if-statement and then redirect the user depending if the user is logged in or not. I think a custom function like
if (logged_in()) { redirect }
Would be more appropriative. But building a library for one function seems unnecessary to me. What should I do?
I need to pull off a pretty long if-statement, but building a library for one function seems unnecessary
It's not at all "unnecessary", neither is it strictly "necessary", but it's probably a good idea to create a library/class for this.
If you have a lot of logic you need to work with, "a pretty long if-statement" for example, using a class can help you break this down into smaller pieces and make the logic more manageable. If you only need to call one public method of the class, like $this->auth->is_logged_in(), there's nothing wrong with that, then you can create a small helper file or wrapper function to call the method, and put the redirect logic there instead of the class. Something like this perhaps:
// Make sure your "auth" library is autoloaded or load it here
function logged_in($redirect = TRUE)
{
$CI =& get_instance();
$logged_in = $CI->auth->is_logged_in();
// Redirect the user...
if ( ! $logged_in AND $redirect)
{
redirect('somewhere/else/');
}
// Or just check if they are logged in
return $logged_in;
}
Using a class/library has many benefits, and with something as complicated as user authorization you will benefit greatly from taking advantage of it, especially once your project starts to expand and you need more utility.
Although helpers are usually preserved for decoupled functions that have nothing to do with your app, I think in this case they are appropriate. Simply create a helper function called is_logged_in.
To learn more about helpers, visit the Docs:
http://codeigniter.com/user_guide/general/helpers.html
symfony 1.4 passing variables between templates and actions
I've got an index page which includes a call to a series of partials through a switch statement; and it works. I now need to restrict access to the partial dependent upon the user's type; furthermore, I believe my switch statement should be in the actions class according to MVC, but I can't get that to work either. This might be better explained through example:
Here's my file structure for the dashboard module:
..dashboard
..actions
..config
..templates
_admins.php
_employers.php
_employees.php
_guest.php
indexSuccess.php
Here is my current indexSuccess template (which currently works... but without restricting access if the logged user's type doesn't match the page type):
$type = sfContext::getInstance()->getUser()->getGuardUser()->getProfile()->getType()->getName();
switch($type)
{
case ('Employer'):
include_partial('dashboard/employers');
$page_user_type = "employer"; //this example line currently does not exist, it's for example purpose below
$break;
case ('Employee'):
include_partial('dashboard/employees');
break;
case ('Administrator'):
include_partial('dashboard/admins');
break;
default: include_partial('dashboard/guest');
break;
}
Here's my actions class (currently empty):
public function executeIndex(sfWebRequest $request)
{
}
Basically, what I need is the switch statement moved to the action (I think), and a forward404Unless() method added that does the following:
$logged_user = sfContext::getInstance()->getUser()->getGuardUser()->getId();
$this->forward404Unless($logged_user == $page_user_type); //where the $page_user_type variable is retrieved by the switch statement in the example line above.
I've tried using the getAttribute() and setAttribute() with no success... and I'd rather not share attempts due to embarrassment. Just a beginner here...
Any help would be appreciated. Thanks in advance.
UPDATE:
Here's more information about the switch and the different partials:
The switch renders a different partial based upon the user's type. What it doesn't do is keep other logged-in users of a different type from accessing all the other partials... which in my design, is very bad. For example: logged-in users of type "employer" may not view the partial of type "employee". Currently they can (by explicitly typing in the other url), even though they are being redirected to the appropriate page during the the index action.
The 404 page should be called when a user of the wrong type tries to access the other partial by explicitly typing in the url. That's why I was attempting to add a variable to the switch statment when the appropriate partial is called and then passing that variable to the index action which would then evaluate it and either permit the partial to be rendered, or if the user_type and partial_type did not match -> forward to a 404 page. Make sense? I hope I explained that thouroughly enough. I'm sure there is an easier way... I'm just not schooled enough to know what that might be.
I sure do appreciate your response and attempt to resolve my issue.
You should play with the credential system to block not authorized user to access a ressource.
The 'type' of your user can become the name of a credential. Then you just have to create the security.yml to handle that.
I'm having a little trouble understanding when the 404 should happen. Does this handle it?
Action:
public function executeIndex(sfWebRequest $request)
{
$this->profileType = $this->getUser()->getGuardUser()->getProfile()->getType()->getName();
$this->forward404Unless(in_array($this->profileType, array('type1', 'type2')), 'Invalid profile type');
}
It's perfectly acceptable to have a switch statement in a veiw, though if that is the entirety of indexSuccess.php you may wish to call sfAction::setTemplate, instead.
Okay, I figured this one out on my own. Here's what I did to get the desired result:
Changed the route so that it cannot be explicitly typed and accessed. Problem solved.
I am using the core Auth component. I have created a user login that manages all of the permissions. The way I am implementing the login monitoring is by checking for $this->Auth->user() in the app_controller. Each time the app_controller cycles the beforeFilter() function and !$this->Auth->user(), it will increment the Captcha.LoginAttempts session variable. When Captcha.LoginAttempts is > 3, I want it to redirect to the Captchas controller, displaying a captcha screen requiring the user to confirm they are a human. (Similar to how stackoverflow does it).
The issue I am having is if I am using an element somewhere or referencing something within the cake framework on the page, it will hit the redirect and cause an endless circular redirect for every accessing element/component being called external to the actual controller/action. Is there a better way to implement this?
Here is the actual code I have been messing with. But it basically sucks (IMO):
// this is in the app_controller beforeFilter() method.
if($this->Auth->user()) {
$this->Session->delete('Captcha');
} else {
$this->Session->write('Captcha.LoginAttempts', $this->Session->read('Captcha.LoginAttempts') + 1);
if ($this->Session->read('Captcha.LoginAttempts') > 3) {
if (!$this->Session->read('Captcha.controller')) {
$this->Session->write('Captcha.controller', $this->params['controller']);
$this->Session->write('Captcha.action', $this->params['action']);
}
if ($this->Session->read('Captcha.fail') !== 'true') { // avoid circular reference redirects
$this->Session->write('Captcha.fail', 'true');
$this->redirect(array('controller' => 'captchas', 'action' => 'index'));
}
}
}
You can see how I try to avoid the circular reference. But then the user could just go to the login page and since the Captcha.fail session variable is already set, it will ignore the redirect. There must be a more elegant way to implement this. Anyone?
Normally, I would just try to answer the way you are trying to do it, but since you asked for any better ideas, what I would do is have the Captcha actually on the login page and use the AuthComponents builtin methods and properties like loginRedirect, autoRedirect, and allow(). Then, just turn the captcha on/off based on the Captchas.loginAttempts variable.
For your current method, I don't think you're going to get an elegant way of doing this. However, you might be able to change the properties of the AuthComponent to get what you want. You could change loginRedirect and loginAction so that /captchas/index is the new login form, then on successful captcha, set loginAction back to /users/login or whatever. This way, if someone were to attempt to hit /users/login directly without doing the captcha, then the AuthComponent logic would kick in and redirect to /captchas/index.
Here are some relevant manual pages:
http://book.cakephp.org/view/392/loginRedirect
http://book.cakephp.org/view/382/allow
http://book.cakephp.org/view/395/autoRedirect
http://book.cakephp.org/view/391/loginAction
Hope this helps!
I've read quite a few posts that are very similar to the question I'm about to ask, but I just wanted to be sure that there wasn't a more sophisticated way to do this. Any feedback is greatly appreciated.
I want to create a mechanism to check whether or not a logged-in user has access to the php script that is currently being called. If so, the script will continue on; if not, the script just fails out using something like die('you have no access').
I came up with two ways of accomplishing this:
(please assume my session stuff is coded/working fine - i.e. I call session_start(), set up the session vars properly and etc)
Define a global variable first, then check the global variable in a required header file. For example:
Content of current_executing_script.php:
// the role the logged in user must have to continue on
$roleNeedToAccessThisFile = 'r';
require 'checkRole.php''
Content of checkRole.php:
if ($_SESSION['user_role'] != $roleNeedToAccessThisFile) die('no access for you');
Define a function within the header file and call the function immediately after including/requiring it:
Content of checkRole.php:
function checkRole($roleTheUserNeedsToAccessTheFile) {
return ($_SESSION['user_role'] == $roleTheUserNeedsToAccessTheFile);
}
Content of current_executing_script.php:
require 'checkRole.php';
checkRole('r') or die('no access for you');
I'm wondering if there is a way to basically just pass a parameter to checkRole.php as part of the include or require construct?
Thanks in advance.
There isn't a way to pass parameters to include or require.
However the code that is included joins the program flow at the point where you include it, so it will inherit any variables that are in scope. So for example if you set $myflag=true immediately before the include, your included code will be able to check what $myflag is set to.
That said, I wouldn't suggest using that technique. Far better for your include file to contain functions (or a class) rather than code that gets run straight off. If you've included a file containing functions then you can call your functions with whatever parameters you want at any point in your program. It's much more flexible, and generally a better programming technique.
Hope that helps.
This could be a useful workaround.
Register a function in say functions.php:
function get_template_partial($relative_include_path, $scoped_parameters)
{
$base_partial_directory = get_template_directory() . '/partials/';
return include $base_partial_directory . $relative_include_path;
}
Use the $scoped_parameters in the partial /partials/role-check.php:
$args = [
'id' => $scoped_parameters['user_id']
];
// A few moments later...
return [
'role_required' => 'admin'
];
Altogether now...
$partial_return_data = get_template_partial('role-check.php', [
'user_id' => 328
]);
echo $partial_return_data['role_required']; // admin
The only thing I can remember with this is if you're using an IDE it might complain that $scoped_parameters is undefined but it's not a third world issue I suppose.
You could have the required file return an anonymous function, and then call it immediately after.
//required.php
$test = function($param)
{
//do stuff
}
return $test
//main.php
$testing = require 'required.php';
$testing($arg);
In the past, many people have disagreed with this approach. But I think it is a matter of opinion.
You can't pass _GET or _POST param via a require() or include() , but you can you first set a _SESSION key/value and pull it on the other side.