public function login() {
//if already logged-in, redirect
if($this->Session->check('Auth.User')){
$this->redirect(array('controller'=>'pages','action' => 'index'));
}
// if we get the post information, try to authenticate
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$status = $this->Auth->user['status'];
if($status != 0){
$this->Session->setFlash(__('Welcome, '. $this->Auth->user('username')));
$this->redirect(array('controller'=>'pages','action' => 'index'));
}else{
$this->Session->setFlash(__('The user is not active'));
}
} else {
$this->Session->setFlash(__('Invalid username or password'));
}
}
}
why I use this function for login . At first time I login with status 1 the system report user is not active but I login at second time with status 1 ok .
change
$status = $this->Auth->user['status'];
to
$status = $this->Auth->user('status');
user is a function in AuthComponent
If you want to only log users with status = 1, you can also try to use the scope
example:
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'scope' => array('status' => '1')
),
)
),
);
Related
I have created a little project with an admin section. I am using admin routes to redirect to admin actions in my controllers. The website has pages that are available to everyone with no login required. To access the /admin or /admin/users, etc... You must login.
I have spread my admin actions across my controllers like "admin_login", "admin_users", ...
So my question is, when someone goes to /admin/users or some other adminpage, I have to check in each controller action if the user is in the session and otherwise redirect to thelogin form.
Is there a way to do this in one place? I used a beforefilter in my AppController class.
When using something like this, I get an infinite loop:
AppController.php
class AppController extends Controller {
public $helpers = array('Paginator','Acl.AclHtml');
public $components = array('Acl', 'Session',
'Auth' => array(
'authError' => 'You are not authorized to access that location.',
'authorize' => array(
'Actions' => array(
'actionPath' => 'controllers')
),
'controllers' => array('users')
));
public function beforeFilter() {
if(isset($this->request->prefix) && ($this->request->prefix == 'admin')){
$username = $this->Session->read('Admin.username');
if (empty($username)) {
$this->redirect (array(
'controller'=>'users',
'action'=>'login',
'admin'=>true
));
} else {
$this->redirect (array(
'controller'=>'admin',
'action'=>'dashboard',
'admin'=>true
));
}
}
// LDAP
$server_ip = $_SERVER['SERVER_ADDR'];
$ldapIp = ClassRegistry::init('LdapIp');
$ldapIpCount = $ldapIp->find('count', array('conditions' => array('ldap_ip' => $server_ip)));
if ($ldapIpCount >= 1) {
$this->Auth->authenticate = array('Ldap');
} else {
$this->Auth->authenticate = array('Form');
}
$this->Auth->authenticate = array('Form');
$this->Auth->allow();
if (!$this->Auth->isAllow($this)) {
$this->set(array(
'message' => array(
'text' => __('un aunthaticated request'),
'type' => 'error',
'status' => "401"
),
'_serialize' => array('message')
));
throw new ForbiddenException();
}
}
}
The front login with LDAP (Active directory).
UsersController.php
App::uses('AppController', 'Controller');
App::uses('Sanitize', 'Utility');
class UsersController extends AppController {
public $components = array('Paginator', 'Session', 'RequestHandler', 'Auth', 'Acl');
public function admin_login() {
$this->layout = 'admin_login';
if ($this->request->is('post')) {
$username = $this->request->data['User']['username'];
$password = $this->request->data['User']['password'];
$password = Security::hash($password, null, true);
$logged_in = $this->User->find('count', array('conditions' => array('User.username' => $username, 'User.password' => $password, 'User.role' => 'Admin', 'User.active' => 1)));
if ($logged_in >= 1) {
$this->Session->setFlash(__('Login successful!'), 'default', array('class' => 'alert alert-success'));
$users = $this->User->find('first', array('conditions' => array('User.username' => $username, 'User.password' => $password, 'User.role' => 'Admin', 'User.active' => 1)));
$this->Session->write('Admin.id', $users['User']['id']);
$this->Session->write('Admin.username', $users['User']['username']);
$this->Session->write('Admin.group_id', $users['User']['group_id']);
$this->Session->write('Admin.full_name', $users['UserProfile']['fname'] . " " . $users['UserProfile']['lname']);
$this->redirect(array('controller' => 'admin', 'action' => 'dashboard', 'admin' => true));
} else {
$this->Session->setFlash(__('Username or password is incorrect!'), 'default', array('class' => 'alert alert-error'));
}
}
}
public function admin_logout() {
$this->Session->delete("Admin");
//$this->Session->destroy();
$this->Session->setFlash(__('Logged out successful!'), 'default', array('class' => 'alert alert-success'));
$this->redirect(array('controller' => 'users', 'action' => 'login', 'admin' => true));
}
}
Yoy are getting an infinite loop because beforeFilter() will be called when you attempt to access /admin/users/login.
The proper way of dealing with your needs is setting up the Auth Component.
Once you've set up component, in UsersController::beforeFilter() you have to allow access to those actions that don't require login by means of the allow() method. E.g.
public function beforeFilter() {
$this->Auth->allow(array('signup'));
parent::beforeFilter();
}
This is also applicable to any other controller with actions that need to be accessed by non logged in users.
The loginAction you define in the Auth component configuration will be automatically allowed access.
In the blog tutorial you will find a good example of the Auth component usage.
Edit
As mentioned, AppController::beforeFilter() is always called, even when you try to access /admin/users/login. To prevent this from happening, try adding the following condition:
if (empty($username) && $this->action!='login') {
$this->redirect (array(
'controller'=>'users',
'action'=>'login',
'admin'=>true
));
}
You wouldn't need this if you allowed AuthComponent to take care of authentication for you.
Still, there's no guarantee that your code will work as expected. You are making your life difficult by not using AuthComponent to its fullest. I recommend that you research on the topic:
Creating Custom Authorize objects in the Cookbook 2.x
LdapAuth in cakephp 2.0 in Stack Overflow
Sorry to bring this topic up again, but I've searched all the answers I can on this topic, but have not found a solution(I'm very new to cakephp):
I use the password routine to hash my password
in my AppController I have:
class AppController extends Controller {
public $components = array('DebugKit.Toolbar','Session','Auth');
}
in my UsersController I have:
public function add() {
if ($this->request->is('post')) {
$this->User->create();
// hash the password coming in from the form using Authcomponent::password
$this->request->data['User']['password'] = AuthComponent::password($this->request->data['User']['password']);
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
/** login method */
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
//redirect to page he was trying to access before login
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Session->setflash('Invalid username or password');
}
}
}
The issue is that I cannot log back in after adding a user: I get the setflash message. The password is being hashed correctly on the MySQL database.
Any help appreciated: I'm at a loss how to debug this.
EDIT
I've tried other solutions, from the cakephp site (no success) and 2 youtube sites (no success). I have also tried plain passwords and hashed passwords (using the default and blowfish) all with the same result.
I have added the debug statements to the code as follows:
public function login() {
pr($this->request->data); //debug
if ($this->request->is('post')) { //devbug
echo ('post request');} //debug
if ($this->request->is('post')) {
debug($this->Auth->login()); //debug
debug($this->request->data); //debug
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirectUrl());
}
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
The array displayed using pr($this->request->data); shows the correct data, however when I use debug($this->request->data); it shows only 5 characters in the password. Could t his be the issue (or a red herring?)
result as displayed follows:
Array
(
[User] => Array
(
[username] => user
[password] => password
)
)
post request
\app\Controller\UsersController.php (line 18)
false
\app\Controller\UsersController.php (line 19)
array(
'User' => array(
'password' => '*****',
'username' => 'user'
)
)
You should try this
AppController
class AppController extends Controller {
public $components = array(
'RequestHandler','Session',
'Auth' => array(
'Autoredirect'=>false,
'loginRedirect' => array('controller' => 'users', 'action' => 'user_dashboard'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'login'),
'authError' => 'Did you really think you are allowed to see that?',
)
);
UsersController
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
} else {
$this->Session->setflash('Invalid username or password');
}
}
}
Try adding this line in the login function:
public function login() {
pr($this->request->data);//LINE ADDED
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
} else {
$this->Session->setflash('Invalid username or password');
}
}
you will see what data you are passing to the form login.
You are saving an encrypted password, but when you log in your software expects an unencrypted password.
Try to put a password unencrypted to your database and it should work.
Try this here in your app controller:
public $components = array('DebugKit.Toolbar','Session','Auth' => array(
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish',
),
)
));
If that is still not working, please post your login-form as well.
In my config.php file, this is the default router.
Router::connect('/', array('controller' => 'users', 'action' => 'signup'));
If users are not connected, they do not have the right to access to the edit actions and view action in the UsersController .
<?php
class UsersController extends AppController{
public $uses = array('User', 'Company', 'Town');
public function beforeFilter(){
parent::beforeFilter();
// If the user is not connected he can't access to these pages
$this->Auth->deny('view', 'edit');
}
}
When users use the login form and are logged in, they are redirected to the page controller and index action.
I would like that they can not enter (user and admin role) to the action signup of the controller Users.
Therefore changed the default route when the user is connected (either admin or user) . But i don't know in my case what i should do .
AppController :
<?php
class AppController extends Controller{
public $helpers = array('Text','Form','Html','Session','Cache');
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'pages', 'action' => 'index'),
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email')
)
)
)
);
function beforeFilter(){
$this->Auth->loginAction = array('controller'=>'users','action'=>'login','admin'=>false);
//tell Auth to call the isAuthorized function before allowing access
$this->Auth->authorize = array('Controller');
//allow all non-logged in users access to items without a prefix
if(!isset($this->request->params['prefix'])){
$this->Auth->allow();
}
if(isset($this->request->params['prefix']) && $this->request->params['prefix'] == 'admin'){
$this->layout = 'admin';
}
// Si l'utilisateur est connecté
if (isset($this->Auth) && $this->Auth->user('id')) {
$this->layout = 'user';
}
}
function isAuthorized($user){
if(!isset($this->request->params['prefix'])){
return true;
}
$roles = array(
'admin' => 10,
'user' => 5
);
return false;
}
}
Thanks .
I found a way to do what I wanted without using ACLs but I do not know if this is the best solution and if it is safe, what do you think?
In Appcontroller in the action beforefilter ()
$role = $this->Auth->user('role');
if ($role == 'user' || $role == 'admin' && $this->request->params['controller'] == 'users' && $this->request->params['action'] == 'signup') {
$this->redirect(array('controller' => 'pages', 'action' => 'index'));
}
I'm trying to implement a login feature where a user can use his username or email address. I've worked out the login with both, but when the user logs in successfully with his email address, the authError still flashes (user is logged in). I've put a comment "HERE" down in the login action, and I'm not sure what happens after that with the redirect.
Here are the relevant bits of my code:
App Controoler:
public $components = array(
'Auth' => array(
'authorize' => 'controller',
'loginRedirect' => array(
'controller' => 'users',
'action' => 'welcome_page'
),
'loginError' => 'Invalid user name/password',
'authError' => 'You don\'t have permission'
),
'Session',
);
User Controller:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add');
}
public function login() {
// At this point, the Auth Component is unable to log in user, so check with email.
if (!empty($this->data) &&
!empty($this->Auth->data['User']['username']) &&
!empty($this->Auth->data['User']['password'])) {
// Look for user with email address using the entered username
$user = $this->User->find('first', array(
'conditions' => array(
'User.email' => $this->Auth->data['User']['username'],
'User.password' => $this->Auth->data['User']['password']
),
'recursive' => -1
));
// Check if a matching user is found and that if login was succesfull
if (!empty($user) && $this->Auth->login($user)) {
if ($this->Auth->autoRedirect) {
// NOTE: user trying to log in with email reaches HERE
$this->redirect($this->Auth->redirect()); // this is the default authentication redirect defined in App Controller
}
} else {
$this->Session->setFlash($this->Auth->loginError, $this->Auth->flashElement, array(), 'auth');
}
}
}
I edited your original post to delete the messages from the session variables.
<?php
$this->Session->delete('Message.flash');
$this->Session->delete('Message.auth');
?>
Hope this helps!
-Andrew
I want to create an admin panel for my site, for this I've created admin.ctp. In DB table name user contain column role, where role=admin/regular(user).
There is only one login form, and the question is, Is it possible to place a 'check' that if user.role=admin then redirect to the admin/user/dashboard and if user.role=regular then layout=default? my AppController.php contains:
function beforeFilter(){
$this->Auth->allow('index','view','login','home');
$this->set('admin',$this->_isAdmin());
$this->set('logged_in',$this->Auth->loggedIn());
$this->set('current_user',$this->Auth->User());
if ((isset($this->params['prefix']) && ($this->params['prefix'] == 'admin'))) {
$this->layout = 'admin';
}
And usersController.php
function beforeFilter(){
parent::beforeFilter();
$this->Auth->allow('*');
if($this->action=='add' || $this->action=='edit'){
$this->Auth->authenticate=$this->User;
}
}
function login(){
if(!($this->Auth->loggedIn())){
if ($this->request->is('post')) {
if ($this->Auth->login()) {
if($user['role'] === 'admin'){
$this->redirect($this->Auth->redirect('admin',array('controller' => 'user','action' => 'admin_dashboard')));
}
$this->redirect($this->Auth->redirect(array('controller' => 'posts','action' => 'index')));
} else {
$this->Session->setFlash('Your username/password combination was incorrect.',
'alert',array(
'plugin' => 'TwitterBootstrap',
'class' => 'alert-error'
));
$this->set('forget', 'Forgot Your Password');
}
}
}else
{
$this->redirect($this->Auth->redirect(array('controller' => 'posts','action' => 'index')));
}
}
using cakephp 2.2.3.
thanks in advance!
This is how I would do it (remember to change field('name') accordingly with your group model).
if ($this->Auth->login())
{
this->User->Group->id = $this->Auth->user('group_id');
switch ($this->User->Group->field('name'))
{
case 'admin':
$this->redirect($this->Auth->redirect('admin',array('controller' => 'user','action' => 'admin_dashboard')));
break;
case 'regular':
$this->redirect($this->Auth->redirect(array('controller' => 'posts','action' => 'index')));
break;
default:
//...
break;
}
}
In AppController set:
$this->Auth->authorize = array('Controller');
And then do the following
public function isAuthorized($user = null)
{
if (isset($this->request->params['admin']))
{
if(!isAdmin)
{
return false;
}
}
return true;
}
CakePHP actually already provides a useful Authentication and Authorization framework that's trivial to enable.
Here's how to authorize based on a role stored in the database, from the CakePHP manual. I also included an example beforeFilter() that changes the login redirect action if the user is an admin:
AppController.php:
public $components = array(
'Auth' => array(
'authorize' => array('Controller'),
'loginRedirect' => array('/'),
));
public function beforeFilter() {
// This allows us to use $user in all controllers.
$this->set('user', $this->Auth->user());
// If the user is an admin, override the loginRedirect
if ('admin' === $this->Auth->user('role')) {
$this->Auth->loginRedirect = array(
'controller' => 'users',
'action' => 'admin_dashboard',
));
}
}
UsersController.php:
public function isAuthorized($user) {
// Ensure the user has a valid role. If not, deny access to all actions:
if ((!isset($user['role'])) || ('' === $user['role'])) return false;
// If we're trying to access the admin view, verify permission:
if ('admin_dashboard' === $this->action)
{
if ('admin' === $user['role']) return true; // User is admin, allow
return false; // User isn't admin, deny
}
return true;
}
There are many ways you can arrange the authorization, so adjust the if/else statements to best suit your needs. The isAuthorized() method is relatively simple, you just need to return true if you want to allow access, or false if you don't.
I actually want to post some code to perhaps shed light on this subject for myself as well.
I have achieved a simple dashboard for each user that extends the /Users/view - my next step is trying to get User-specific access to each set of data
AppController
class AppController extends Controller {
public $components = array(
'Acl',
'Auth' => array(
'authorize' => array(
'Actions' => array('actionPath' => 'controllers')
)
),
'Session'
);
public $helpers = array('Html', 'Form', 'Session');
public function beforeFilter() {
//Configure AuthComponent
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'dashboard');
$this->Auth->allow('display');
}
}
UsersController
public function dashboard() {
$id = $this->Auth->user('id');
$this->set('user', $this->User->read(null, $id));
$group_name = $this->User->Group->field('name', array('id' => $this->Auth->User('group_id')));
$this->redirect = array('controller' => 'users', 'action' => 'dashboard');
}
dashboard.ctp
$this->extend('/Users/view');
<?php public function dashboard() {
$id = $this->Auth->user('id');
$this->set('user', $this->User->read(null, $id));
$group_name = $this->User->Group->field(
'name', array('id' => $this->Auth->User('group_id'))
);
$this->redirect = array('controller' => 'users', 'action' => 'dashboard');
}
?>