I'm aware there's a similar post to this but just to confirm my understanding.
I just start using Yii2 PHP. I've used dektrium/yii2-user that can login and register. I want to do a beforeAction() to check logged user auth.key if exist in database (XAMPP MYSQL). Below is the code I want to performed on.
//Action direct to json.php.
public function actionJson()
{
return $this->render('json');
}
If the statement true will direct to the page, else shows a alert error.
I know the exact code is
public function beforeAction($action){}
What I'm confused on is where do I actually put beforeAction() at.
BeforeAction()
This method is invoked right before an action is executed.
https://www.yiiframework.com/doc/api/2.0/yii-base-controller#beforeAction()-detail
Where to place it?
You must place it inside your login controller (LoginController.php) class.
Remember to call the parent inside the function as :
public function beforeAction($action)
{
if (!parent::beforeAction($action)) {
return false;
}
return true; // or false to not run the action
}
Then all the actions from that controller will use your custom beforeAction function.
Related
I have an application where I will be storing links in the database allowing the user to assign actions to the link. I want to avoid the situation where the action does not exist and I get this error;
Action App\Http\Controllers\PermissionController#index2 not defined.
So I would like to check whether an action exists and has route. If possible in blade but anywhere else is fine.
There isn't any built in way to do this. But we have a action helper method which generates route url based on the controller action. We can make use of this and create a simple helper function to achieve the same result. The method also checks if the given controller method is linked to a route, so it does exactly what you need.
function action_exists($action) {
try {
action($action);
} catch (\Exception $e) {
return false;
}
return true;
}
// Sample route
Route::get('index', 'TestController#index');
$result = action_exists('TestController#index');
// $result is true
$result = action_exists('TestController#index1');
// $result is false
You could also verify the existence of the action method using the class directly, but this would return true if the method exists but isn't linked to a route.
Edit: Version: 2.5.7
I'm currently trying to setup role based authentication with CakePHP. So far I've managed to get authentication to work ok, where controller access redirects to a login screen when not authenticated, and permits access when I am authenticated..
My problem comes when I want certain 'admin' level access to certain action methods, (prefixed with admin_) yet denies them for regular logins.
If I uncomment $this->Auth->authorize in the beforeFilter, my authentication works fine..Comment it in, and I can't log in.
AppController
public function isAuthorized() {
if (!empty($this->params['action']) && (strpos($this->params['action'],'admin_') !== false) ) {
if ($this->Auth->user('admin')) {
return true;
}
}
return false;
}
public function beforeFilter()
{
$this->Auth->authorize = 'controller';
$this->Auth->deny(); //deny everythng
}
My Dashboard controller is the first screen after successful login. It's before filter just looks like this. Do I need to put a parent:: isAuthorized call somewhere? Or when exactly is the isAuthorized call made? I can tell it is firing, but just not sure why I get kicked back to the login screen when I implement it.
Dashboard Controller.
public function beforeFilter()
{
parent::beforeFilter();
}
Kind of found a solution (of sorts)
Cookbook tells you to do this: http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html
(See under PostController). I whitelist the actions I want regular logged in users to see, and the parent isAuthorized handles the admin scenarios.
Dashboard Controller
public function isAuthorized($user) {
$actions = array("stats","index");
if (in_array($this->action, $actions)) {
return true;
}
return parent::isAuthorized($user);
}
Problem with this approach is that its pretty painful to have each of my controllers having this sort of white list code in each one. Feels ugly to me.
I have a Controller witch contains more than 150 functions. almost all of the functions inside the controller are returning views.
each view should change if the user is logged in.
I almost handled this in the view side by using parent blades and etc. But in the controller side for almost every function i should check if the user is logged in and return some specific data about the user along with the view.
for example:
$user=[];
if(Auth::check())
{
$user=Auth::user;
$reputation=$user['reputation'];
$messages=$user->messages();
$notifications=$user->notification();
}
return view('pages.profile')->with(['user'=>$user , 'messages'=>$messages , 'notifications'=>$notifications]);
I thought that this is possible using middlewares but i could not figure it out.
what are the alternatives here?
for more information i am using laravel 5.
One solution could be using your custom function instead of view(). Sth like:
//in your controller action
public function someAction() {
return $this->view('pages.profile');
}
protected function view($template, $data = array()) {
return view($template)->with($data)->with([data that needs to be passed to all views]);
}
im doing this;
example core/MY_CONTROLLER.php
private $action_user=null;
public function __construct()
{
parent::__construct();
##listen for post attempts;
$this->validate();
##set action_user; return null if no session else return user object
$this->action_user = $this->session->userdata('loged_user');
##extra check step
if($this->user->pwd_has_changed($this->action_user)){
$this->session->sess_destroy();
alerts('error','the password you used to login has changed ! please relogin');
return $this->failed_login();
}
}
public function alerts(){return die(json_encode(alerts()));}#a helper function.. just ignore it for this example
public function logout(){$this->session->sess_destroy();redirect();}
#AUTH
private function failed_login(){
//$callers=debug_backtrace();
alerts('warning','failed login');//.' '.$callers[1]['function']);
ob_clean();//clear flush just to make sure !
if($this->input->is_ajax_request())$this->load->view('base/ajax/landing');
else $this->load->view('base/landing');
die($this->output->get_output());//kill request and load landing in same uri. this in case he attempt login again he will be at same url; also helps with partials views
}
private function success_login(){
unset($_POST['login'],$_POST['password']);
alerts('success','welcome '.$this->action_user->login);
//nothin much to do.. just dont die
}
private function validate(){
//listen to posts if so logout and relog in
if( !$this->input->post('login') || !$this->input->post('password'))return FALSE;
$this->session->sess_destroy();#destroy session
#1. validation
$this->form_validation->set_rules('login', 'User Login', 'required|min_length[4]|max_length[12]|xss_clean');
$this->form_validation->set_rules('password', 'Password', 'required|min_length[4]|max_length[12]|xss_clean');
#1.2 Failed validation
if( ! $this->form_validation->run() )return alerts('error',$this->form_validation->error_string(),false);#set message and return false
#2. Login
$this->user->login(set_value('login'),set_value('password'));
//i dont want it to return anything ! $this->user->login should set messages of success OR fail + set user session
}
public function auth($role = null){
if(!isset($this->action_user->id))
return alerts('error',"this is a users restricted area",$this->failed_login());
//ACCESS LEVELS CONDITIONS
if($this->user->in_group($this->action_user->id,$role))return $this->success_login();
return alerts('error',"this is a {$role} restricted area",$this->failed_login());
}
#END AUTH
now in my controller constructor; since MY_CONTROLLER constructor is called first; so i should hv retrieved $action_user object; or already attempted to log him in.
if i want to restrict a page i just add
$this->auth();
//or $this->auth('admin');
to its constructor and if user is not allowed page will die and send him my view page without redirect;
the reason im using such approach is let user be able to login,logout from any controller;
if he visit http://localhost/RANDOMECONTROLLER/logout he will still logout.. same for login.
also its helpful that sometimes when i get page partials by ajax; it will just return a landing page into this div with login form.
example
a statistics page have 4 widgets, 1 of them is only viewable by admin;
then when ajax fitch 4 widgets, it will show 3 and a div with login form saying you need to be an admin to login..
...
so do you think this is a good way to do this ? or is it bug gable spaghetti ** ?
This is not a good practice. The best practice is to create a Secure_Controller that extends MY_Controller. If you have a controller with auth you need to extend Secure_Controller, but if you have another without auth you need yo extend MY_Controller.
There are lots of libraries for codeigniter auth easy to extend and adapt to your requirements, for example Ion Auth.
i have login form, and then i try to access the controller directly, it works ! how do i prevent this access ?
i got some class
class C_home extends CI_Controller{
public function __construct() {
parent::__construct();
$this->session->set_userdata('islogin'); //to set session islogin
}
function index()
{
if ($this->session->userdata('islogin') != TRUE)
{
redirect('c_home','refresh'); //caused infinite refresh
}
redirect('c_login', 'refresh');
}
}
then i try to direct access controller, the page show infinite refresh, i want the page to show the login form
how do i resolve this ?
A couple of comments:
On the $this->session->set_userdata('islogin'); line, you should pass a 2nd argument which is the value to be assigned (presumably, TRUE is what you meant to put)
I think your redirect lines are the wrong way around. If the user isn't logged in, then you want to redirect to login. Now what your code does is redirect to home if the user isn't logged in, hence the endless loop (since this code is in the home page!
The $this->session->set_userdata('islogin', TRUE); line should obviously be in your login controller, but I'm guessing you've put it here just for testing purposes?
I'd rather do this like so
class C_home extends CI_Controller {
public function __construct()
{
parent::__construct();
}
function index()
{
if ($this->session->userdata('islogin') != TRUE)
{
redirect('c_home/login','refresh'); // go for login
}
// do something for loged in users here
}
function login()
{
if ($this->session->userdata('islogin') == TRUE)
{
redirect('c_home','refresh'); // get back home
}
// perform some login logic here
// then, if successful
{
$this->session->set_userdata('islogin',TRUE);
redirect('c_home','refresh'); // get back home
}
// or else
// display login form here
}
Of course is always better to use third party login library like this one https://github.com/DaBourz/SimpleLoginSecure
You're supposed to access the controller, that is the point of them to control things. If you have specific functions you don't want accessed via URL then prefix the function name with an _ like _notForPublicFunction. As to the infinite refresh...
if(!$this->session->userdata('isLogin'))
{
redirect('c_login');
} else {
redirect('c_home');
}
What you need to do is set up a base controller that will look after the session for you and split your logged in controllers from your logged out ones via inheritance.
It is a common question on here how best to manage logged-in and logged-out states. Please refer to this answer for detailed explanation on how to do it.