Cakephp how to redirect from beforeRender method in AppController? - cakephp

User case I'm trying to do, if a user not submit his company details always redirect user to company page.
In appController I have written like below beforeRender method
public function beforeRender(\Cake\Event\EventInterface $event) {
if( !is_null($this->Auth) )
{
if($this->getTable('Users')->hasCompany($this->Auth) == false){
return $this->redirect(['controller'=>'Companies','action'=>'edit']);
}
}
}
Here hasCompany method always return true or false. Here I'm trying to redirect user if hasCompany == false. But problem is like infinite loop browser just reloading.Redirection are not working.

Related

Cakephp: AuthComponent Evaluation Order and how to redirect to an action

good day everyone, regarding auth component I am doing some tests to understand better the tool, in a probe of concept i want that an authenticated admin user be authorized to access any action, but if the authorized user has the "supervisor" role only be able to the actions index, view and edit in the "RequestsController.php", I am trying this approach:
1) allow everything for admin role and deny everything for anyone else in AppController.php.
2) Allow explicitly "supervisor" in "RequestsController.php" and deny any other role.
The doubt is that after some tests what happens is that if I authorize the admin user just in AppController.php the redirects only allows me to go to /webroot/, but If I allow the admin role in RequestsController.php. I can see requests without problem
IsAuthorize method in AppController
public function isAuthorized($user)
{
//privileges 1 means admin
if ($user['privileges']==1){
debug($user);
return true;
} else {
debug($user);
return false;
}
}
IsAuthorize method in Requests Controller
public function isAuthorized($user)
{
//privileges 9 means supervisor
if ($user['privileges']==9){
debug($user);
$action = $this->request->getParam('action');
if (in_array($action, ['index', 'view', 'edit'])) {
debug($user);
return true;
}
return false;
} else {
debug($user);
return false;
}
}
As I am not clear in the order that the isAuthorized function is handled, or why the redirect to the Request (even if it is "AppController.php" or "RequestsController.php") So this makes me think that I'll have to explicity authorize the admin role in all controllers
When using ControllerAuthorize, AuthComponent will call isAuthorized() method only on active controller. So, in your example, when requesting any action from RequestsController, only RequestsController::isAuthorized() will be called, disallowing access to users which has priviledge other than 9.
If you want to allow admin users to access as well, you should change your RequestsController::isAuthorized() as follows:
public function isAuthorized($user)
{
//privileges 9 means supervisor
if ($user['privileges']==9){
debug($user);
$action = $this->request->getParam('action');
if (in_array($action, ['index', 'view', 'edit'])) {
debug($user);
return true;
}
return false;
} else {
debug($user);
return parent::isAuthorized($user); //changed this line
}
}
Additional info: CakePHP 3.x AuthComponent - Authorization

How to redirect url from angularjs login submission via laravel 5

i'm developing my website with angularjs and laravel5. i wrote code for login and registration page in both angularjs and laravel5 where validate my value and insert everything works good but redirect url in laravel 5 not occur .
i wrote code like return redirect('Home/profile') in login controller. it returns total page to angularjs controller not redirecting page.
routes.php in laravel:
Route::group(array('prefix'=>'api'),function(){
Route::resource('register','Registration\RegisterController#basicForm');
Route::resource('login','Registration\RegisterController#makeLogin');
});
my controller :
public function makeLogin()
{
$email=Input::get('email');
$pwd=Input::get('pwd');
$verify=Authenticated::attempt($email,$pwd);
if($verify)
{
return redirect('Home/profile');
}
else if($verify=='user')
{
return redirect('/')->with('Email address mismatch');
}
else if($verify=='pwd')
{
return redirect('/')->with('Password Authentication Failed');
}
}
i send post request from angular js controller via factory method:
this.scope.authUserInfo.authenticateUser(this.scope.signin).then(function(data){
console.log(data.data);
});
In this console.log,display 'Home/profile' page
I can see many mistakes in the Laravel code.
What is Authenticated in your code? The authentication service in Laravel is called Auth. The way you use the attempt() method is not correct; this is the method signature:
attempt(array $credentials = array(), bool $remember = false, bool $login = true)
so you should pass the email and the password in the first parameter as an array, something like:
$verify = Auth::attempt(['email' => $email, 'password' =>
Moreover, the attempt() method returns a boolean: true on success and false on failure. Your code
if ($verify) {
// ...
} else if ($verify == 'user') {
// ...
} else if ($verify == 'pwd') {
// ...
}
has no sense and you never run the else parts because on failure false is always different from either 'user' or 'pwd'. So, when the authentication fails you reach the end of the makeLogin() method and Laravel returns a blank page.
You should use something like:
if ($verify) {
// authenticated: go to the profile page
} else {
// username OR password are wrong
}
(In my opinion you shouldn't give hints on what of the two is wrong for security reasons: a potential attacker would know if he/she guessed a right email and concentrate the attempts on guessing the password.)
If you really want to give a hint to the user on what was wrong with her data, you should use a different technique, like searching the users table for a record with the right email to know whether the user exists (the provided password was wrong) or not (the provided email was wrong).
On the client side, I don't think Angular will redirect on your own. See answer to Handle an express redirect from Angular POST, even if in that question the server uses ExpressJs and not Laravel, but the basics are the same.
You should understand that in most cases an Angular client expect to receive only data and not a full HTML page. Here is my little attempt to do what you want:
On the Laravel side:
public function makeLogin(Request $request)
{
$email = $request->get('email');
$pwd = $request->get('pwd');
if (Auth::attempt(['email' => $email, 'password' => $pwd])) {
// authenticated!
// if you return an array from a controller public method, Laravel
// will convert it to JSON; I also use the url() Laravel helper to
// generate a fully qualified url to the path
return [
'status' => 'redirect',
'to' => url('home/profile')
];
}
// failed
return [
'status' => 'failed',
'message' => 'Email or password are wrong'
];
}
Now the method will return a JSON answer. On the Angular side, you can do something like (I'm not an Angular guru, there could be mistakes here):
this.scope.authUserInfo.authenticateUser(this.scope.signin).then(function(data) {
if (data.response == 'redirect') {
$location.url(data.to);
} else {
// failed: you can show the error message
console.log(data.message);
}
});
UPDATE
I noticed there is something wrong in the routes too. Your controller does not seems a resourceful controller, so don't use the Route::resource() method. Use the get() and post() methods instead:
Route::group(array('prefix'=>'api'),function(){
Route::get('register', 'Registration\RegisterController#basicForm');
Route::post('login', 'Registration\RegisterController#makeLogin');
});
so that you can give the method that should be called in your controller.

How can you test whether a user is active in Cakephp 2.0 auth component?

I'm having trouble hashing out how to test whether a user is active using the new Auth component. I have 3 states a user can be in: 0 unactivated (default), 1 activated, 2 deactivated. I'm trying to implement this in the login function so I can return whether they haven't registered or have been banned.
Login:
public function login() {
if ($this->request->is('post')) {
if($this->Auth->login()) {
$results = $this->User->find('all', array(
'conditions' => array('User.email' => $this->Auth->user('email')),
'fields' => array('User.is_active')
));
if ($results['User']['is_active'] == 0) {
// User has not confirmed account
$this->Session->setFlash('Your account has not been activated. Please check your email.');
$this->Auth->logout();
$this->redirect(array('action'=>'login'));
}
// not working atm
else if ($results['User']['is_active'] == 2) {
// User has been deactivated
$this->Session->setFlash('Your account has been deactivated. Contact site admin if you believe this is in error.');
$this->Auth->logout();
$this->redirect(array('action'=>'login'));
}
else if ($results['User']['is_active'] == 1) {
// User is active
$this->redirect($this->Auth->redirect());
}
} else {
$this->Session->setFlash(__('Your email/password combination was incorrect'));
}
}
}
Can't see where I've gone wrong. Users with admin privileges and activated users are still getting the unactivated account error.
Update
Decided to drop the User.is_active field and handle it all in roles. I'm handling it in the AppController and it is almost working now. In the isAuthorized function, it now throws errors if the user is banned or unactivated, but I need it to log them out as well.
public function isAuthorized($user) {
// This isAuthorized determines what logged in users are able to see on ALL controllers. Use controller
// by controller isAuthorized to limit what they can view on each one. Basically, you do not want to allow
// actions on all controllers for users. Only admins can access every controller.
if (isset($user['role']) && $user['role'] === 'admin') {
return true; //Admin can access every action
}
elseif (isset($user['role']) && $user['role'] === 'unactivated') { // Account has not been activated
$this->Session->setFlash("You haven't activated your account yet. Please check your email.");
return false;
}
elseif (isset($user['role']) && $user['role'] === 'banned') { // Your account has been banned
$this->Session->setFlash("You're account has been banned. If you feel this was an error, please contact the site administrator.");
return false;
}
return false; // The rest don't
}
If they log in, the User model info can be accessed with $this->Auth->user(). So you should be able to do something like this:
if ($this->Auth->login()) {
if ($this->Auth->user('is_active') == 0) {
// User has not confirmed account
} else if ($this->Auth->user('is_active') == 1) {
// User is active
// and so on
You can use debug($this->Auth->user()); after the login() to see why the users keep showing as unactivated.
Now, in year 2021, for CakePHP 4.x this is the correct approach:
if ( $result->isValid() ) {
if ( $this->getRequest()->getAttribute('identity')->is_active ) {
// The user is active and can log in
} else {
// The user is not active - reject the log in
}
}

CakePHP: login fails following a specific set of steps

I'm trying to set up a simple login system, but I'm having a particular problem that I can't solve. I have the following pages that perform self-explanatory actions. They are bookmarked for easy access.
cake/ (home page; must be logged in)
cake/login (must be logged in)
cake/logout (must be logged in)
cake/add (must be logged in)
All seems to work except when I preform the following sequence of actions:
1. log in
2. go to cake/logout to log out (login works immediately after this step)
3. go to cake/logout again immediately
4. attempt to log in but cake/login is just re-displayed and I'm not logged in
5. attempt to log in again and it is successful
I have noticed that $this->Session->flash('auth') is FALSE after step 3 but it is not false after 4. I tried destroying the session before or after logging out with no effect. Any ideas?
My code bits are below:
class UsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
}
public function add() {
if (!empty($this->data)) {
$this->User->create();
if ($this->User->save($this->data)) {
$this->Session->setFlash('User created!');
$this->redirect(array('action'=>'login'));
} else {
$this->Session->setFlash('Please correct the errors');
}
}
}
public function login() {
}
public function logout() {
$this->Session->destroy(); // makes no difference
$this->redirect($this->Auth->logout()); // redirected to login() by default
}
}
class AppController extends Controller {
public $components = array('Auth', 'Session');
}
I think that you are being redirected to the logout screen after your login.
When you go to a page you don't have access to (like the logout screen), you are redirected to login.
Once you enter name and password, you are taken back to your original request.
When that original request happens to be the logout page, logout occurs and you are sent back to the login.

change details before Cakephp Auth compontent reads the database

Does someone here know how to change the username before the Auth component reads the database?
The problem im having is im using mobile numbers as a login but i want to add the country code (if not present) when loggin in to my site
Any one have an idea on this?
Would be appreciated
If you are using CakePHP 2.0, you can manipulate the login form data as usual and then call $this->Auth->login(). Example:
// in your controller
public function login() {
if ($this->request->is('post')) {
$this->data['User']['username'] = $this->addCountryCode($this->data['User']['username']);
if ($this->Auth->login()) {
// login successful
} else {
// login not successful
}
}
}
you could always extend the Auth component and do whathever you want before the asking the database :)
Something like this...
function login($data = null,$public = false) {
$this->__setDefaults();
$this->_loggedIn = false;
if (empty($data)) {
$data = $this->data;
}
if (/** query the database to check/modify the data. You could use the identify() method of the AuthComponent **/) {
$this->Session->write($this->sessionKey, $user);
$this->_loggedIn = true;
}
return $this->_loggedIn;
}
If you extend the auth component, remember to always use this component instead of the default Auth class. (e.g. in the AppController, the build_acl, the initdb, the beforefilter on the controllers, etc.)
Hope this helps

Resources