Codeigniter Hooks advance - codeigniter

Hello i am using post_controller hooks to validate user whether logged in or not
But when validation fails i redirect user to login controller....
Now the problem is when it redirect to defaults controller post_controller hooks is called again and in this way infinite loop starts with redirection repeatedly.
i want to call post_controller hook for every controller except login controller....
also is there way that i don't need to load session library again and again because, if user is logged in then it loads session library in post controller as well as via auto-load in config file...
Here is my code
//Hooks
$hook['post_controller'] = array(
'class' => 'is_login',
'function' => 'index',
'filename' => 'is_login.php',
'filepath' => 'hooks'
);
//Is_Login Hook
class is_login {
function __construct(){
$this->CI =& get_instance();
if(!isset($this->CI->session)) //Check if session lib is loaded or not
$this->CI->load->library('session'); //If not loaded, then load it here
}
public function index()
{
$login_id = $this->CI->session->userdata('login_id');
$login_flag = $this->CI->session->userdata('logged_in');
if ($login_flag != TRUE || $login_id == "")
{
redirect(site_url().'/welcome_login', 'refresh');
}
}
}

It seems it is not a good place to use Codeigniter hooks. It is better if you extend the Controller class in your application and in the constructor you can check if user is logged in and redirect to login controller. But no need to extend the login controller from your controller instead extend it from CI_Controller.

I validate logins by hooks without problem. I just generate the login view when logged out and exit the application so that the only thing showing is the login, and the controller (and rest) gets ignored.
There's no need for redirect, really.

if ($this->CI->uri->segment(1) != 'auth') {
//Authenticate
if (empty($user->user_id))redirect('auth');
}

Related

Adding a post_system hook from inside a controller method in CodeIgniter

I have some code i want to work after the request is sent to the client and closed so i want to add a post_system hook to the system from inside a controller, so the post_system hook runs only when specific method is invoked.
does CodeIgniter allow that in some workaround?
My version is 3.0rc3
It should be possible. One approach is to setup the post_system hook as described in the documentation - $config['enable_hooks'] = TRUE;, define the hook in application/config/hooks.php, and write the hook class.
In the controller that will use the post_system hook define a var that will be used to decide if the hook function should actually run. Set the default value to FALSE in the constructor and set it TRUE in specific method you have in mind.
Check the value of this var in your post_system_hook function. You may want to start by checking that the controller is the one that should be hooked. Let's assume that class is 'Welcome';
post_system_hook_function(){
//the type of $CI will be the name of the controller
if(get_class($CI) !== 'welcome') {
return false;
}
if(! $var_that_flags_do_the_task){
return false
}
//do post system code here
}
i understand that you want to check a controller like if it has permition to be in ther like logged.
you need to enable the hook in your application/config/config.php
$config['enable_hooks'] = TRUE;
Then you need to add this lines in your application/config/hooks.php with the code
$hook['pre_controller'] = array(
'class' => 'PreLogin',
'function' => 'auth',
'filename' => 'PreLogin.php',
'filepath' => 'hooks'
);
in your apllication/hooks/PreLogin.php
class PreLogin{
public function __construct(){
$CI =& get_instance();
$this->CI->load->library('session');
}
public function auth(){
if( ! isset($this->CI->session->userdata('id'))){
$this->CI->session->set_flashdata('error', 'You do not have permission to enter this url');
redirect(base_url(), 'refresh');
}
}
}

Before method with multiple role restrictions

Im curious to know if it is possible to prevent users who don't have a role of owner or administrator from accessing certain controllers in a laravel application?
Yes you can. You can do this with a route filter.
routes.php
Route::group(['prefix' => 'admin', 'before' => 'auth.admin'), function()
{
// Your routes
}
]);
and in filters.php
Route::filter('auth.admin', function()
{
// logic to set $isAdmin to true or false
if(!$isAdmin)
{
return Redirect::to('login')->with('flash_message', 'Please Login with your admin credentials');
}
});
Route filters have already been proposed but since your filter should be Controller specific you might want to try controller filters.
First off, lets add this your controller(s)
public function __construct()
{
$this->beforeFilter(function()
{
// check permissions
});
}
This function gets called before a controller action is executed.
In there it depends on you what you want to do. I'm just guessing now, because I don't know your exact architecture but I suppose you want to do something like this:
$user = Auth::user();
$role = $user->role->identifier;
if($role !== 'admin' && $role !== 'other-role-that-has-access'){
App::abort(401); // Throw an unauthorized error
}
Instead of throwing an error you could also make a redirect, render a view or do basically whatever you want. Just do something that stops further execution so your controller action doesn't get called.
Edit
Instead of using Closure function, you can use predefined filters (from the routes.php or filters.php)
$this->beforeFilter('filter-name', array('only' => array('fooAction', 'barAction')));
For more information, check out the documentation

Display message after logout via Silex SecurityServiceProvider

I am using the SecurityServiceProvider to secure my Silex application and would like to display a message after the user has logged out by navigating to the logout_path route.
The message should be stored in the sessions flash bag so that my template can automatically display it after.
I have tried adding an application middleware, but where not able to hook my code in. The before hook doesn't seem to work, because it happens after security and thus after the security's redirected back to my home page.
The before hook with the Application::EARLY_EVENT seems to be to early because as far as I know does the Security provider destroy the session after logout.
Before I keep trying to find a sort of working but probably dirty solution I would like to ask what the best/cleanest solution for this case would be?
UPDATE: After npms hint for a logout event handler I found this article on Google, which describes how to tackle the problem in Symfony very well.
In Silex things are slightly different though and after reading the source of the SecurityServiceProvider I came up with this solution.
$app['security.authentication.logout_handler._proto'] = $app->protect(function ($name, $options) use ($app) {
return $app->share(function () use ($name, $options, $app) {
return new CustomLogoutSuccessHandler(
$app['security.http_utils'],
isset($options['target_url']) ? $options['target_url'] : '/'
);
});
});
class CustomLogoutSuccessHanler extends DefaultLogoutSuccessHandler {
public function onLogoutSuccess(Request $request)
{
$request->getSession()->getFlashBag()->add('info', "Logout success!");
return $this->httpUtils->createRedirectResponse($request, $this->targetUrl);
}
}
The problem however is, that the flashbag message doesn't exist anymore after the redirect. So it seems that the session is being destroyed after the logout success handler is executed... or am I missing something? Is this even the right way to do it?
UPDATE: Still haven't found a proper solution yet. But this works.
I have added a parameter to the target url of the logout and use it to detect if a logout was made.
$app->register( new SecurityServiceProvider(), array(
'security.firewalls' => array(
'default' => array(
'pattern'=> '/user',
'logout' => array(
'logout_path' => '/user/logout',
'target_url' => '/?logout'
),
)
)
));
I had the same problem and your thoughts leaded me to a solution, thank you!
First define logout in the security.firewall:
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'general' => array(
'logout' => array(
'logout_path' => '/admin/logout',
'target_url' => '/goodbye'
)
)
),
));
Create a CustomLogoutSuccessHandler which handles the needed GET parameters for the logout, in this case redirect, message and pid:
class CustomLogoutSuccessHandler extends DefaultLogoutSuccessHandler
{
public function onLogoutSuccess(Request $request)
{
// use another target?
$target = $request->query->get('redirect', $this->targetUrl);
$parameter = array();
if (null != ($pid = $request->query->get('pid'))) {
$parameter['pid'] = $pid;
}
if (null != ($message = $request->query->get('message'))) {
$parameter['message'] = $message;
}
$parameter_str = !empty($parameter) ? '?'.http_build_query($parameter) : '';
return $this->httpUtils->createRedirectResponse($request, $target.$parameter_str);
}
}
Register the handler:
$app['security.authentication.logout_handler.general'] = $app->share(function () use ($app) {
return new CustomLogoutSuccessHandler(
$app['security.http_utils'], '/goodbye');
});
The trick to make this working as expected is to use another route to logout:
$app->get('/logout', function() use($app) {
$pid = $app['request']->query->get('pid');
$message = $app['request']->query->get('message');
$redirect = $app['request']->query->get('redirect');
return $app->redirect(FRAMEWORK_URL."/admin/logout?pid=$pid&message=$message&redirect=$redirect");
});
/logout set the needed parameters and execute the regular logout /admin/logout
Now you can use
/logout?redirect=anywhere
to redirect to any other route after logout or
/logout?message=xyz
(encoded) to prompt any messages in the /goodbye dialog.

Codeigniter: Controller function name shows in url, how change to view file name?

wondering if anyone can guide me to what ive done wrong (or need to do) and think the problem is in my routes file. When the user is displayed the login form and for example they get their username wrong after submit the url displays as this: http://localhost:8888/codeigniter/login/login_validation. When the are successful and log into the admin area (which pulls news articles from the db) this url is still shown. I am wondering if there is a way to make it to http://localhost:8888/codeigniter/news. I have looked in my routes folder and i tried to use 'wildcards' and was unsuccessful. Here is my code for reference, any other info or files needed let me know! Thanks.
CONTROLLER:
class Login extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function index() {
$this->load->view('login');
}
//Validate login area
public function login_validation() {
$this->load->library('form_validation');
$this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean|callback_username_check');
$this->form_validation->set_rules('password', 'Password', 'required|xss_clean|callback_password_check');
if($this->form_validation->run() == FALSE) {
//Field validation failed. User redirected to login page
$this->index();
}else{
$this->load->model('user_model');
$query = $this->user_model->login_details();
// if the user's credentials validated...
if($query) {
$data = array(
'username' => $this->input->post('username'),
'is_logged_in' => true
);
$this->session->set_userdata($data);
redirect('news');
}else{
$data['error'] ="Invalid Username or Password";
$this->load->view('login',$data);
}
}
}
function logout() {
$this->session->sess_destroy();
$this->index();
}
}
login_details function from user_model.php
function login_details() {
$this->db->where('username', $this->input->post('username'));
$this->db->where('password', md5($this->input->post('password')));
$query = $this->db->get('login');
if($query->num_rows == 1){
return true;
}
}
If you're logging into any kind of system, you're going to need to store a session using CodeIgniter's Session class. Provided controllers/news.php exists, you can set the session and immediately just perform a redirect with redirect('news');. No need to $this->load->view() because this logic will be in news.php's index anyway and you'd be duplicating code.
I'm not sure what $this->user_model->login_details() is returning, but I'm assuming false or null because you say CodeIgniter is sending you back to the login view. Head into the login_details() function and make sure things are working properly (you might want to post it too). Also, post your routes.php file for us if you made changes just in case.
On a side note: Space is a valid password character, don't trim it or folks with leading or trailing space's in their passwords won't be able to get in ;)

cannot set user data in session codeigniter

please look at this.
The code below is from my model class (using datamapper orm)
function login()
{
$u = new User();
$u->where('username', $this->username)->get();
$this->salt = $u->salt;
$this->validate()->get();
if (empty($this->id))
{
// Login failed, so set a custom error message
$this->error_message('login', 'Username or password invalid');
return FALSE;
}
else
{
// Login succeeded
$data = array
(
'username' => $u->username,
'usergroup' => $u->usergroup->get(),
'is_logged_in' => true
);
$this->session->set_userdata($data);
return TRUE;
}
}
when i do this i get
**Fatal error: Call to a member function set_userdata() on a non-object**
but when i do this instead
$data = array
(
'username' => $u->username,
'usergroup' => $u->usergroup->get(),
'is_logged_in' => true
);
$obj=& get_instance();
$obj->session->set_userdata($data);
It works.
Please what is the right way to get this working ?
Thanks in advance.
your model did not extends CI_Model
after that you have to add constructor to your model
add this code to yours
function __construct()
{
parent::__construct();
$this->load->library('session');
}
Well, you didn't provide enough information.
The first code looks fine, provided that:
You actually load the session class before calling it (you also need to create an encryption key in your configs).
$this->load->library('session');
$this->session->set_userdata($data);
The above code, or your code, is inside a controller, a model or a view.
$this relates to the CI's superclass, in particular to an instance of the Session class, so if you're calling that inside a helper (collection of functions), or inside a library (where you need to create a CI instance first), it won't work.

Resources