I have 2 authenticate method for Auth component. Default and Special.
First method is for all users, and Special for my friends...
I want to change authenticate method to Special when posted role is equal to 2..
So I put this in my UsersController login method:
if($this->request->data['role'] == 2){
$this->Auth->authenticate = 'Special';
echo 'Method changed!';
}
if($this->Auth->login()){
......
}
and if AppController, where I set $components:
public $components = array('RequestHandler', 'Session',
'Auth' => array('authenticate' => 'Default'));
but, when I send a form with role=2, it prints Method changed but won't change the authenticate method and use Default method..
Have I made a mistake?
I've a simplier solution :
In your controller, define your new authenticate array :
$this->Auth->authenticate = array('Form' => array(
'userModel' => 'User',
'fields' => array('username' => 'login', 'password' => 'password'),
));
Then to make your changes effective in your application, simply write :
$this->Auth->constructAuthenticate();
That's all :)
I've had a similar problem and I solved it by defining the same variable in the beforeFilter action of the AppController:
function beforeFilter() {
parent::beforeFilter();
// Pass settings in
$this->Auth->authenticate = array('Form' => array(
'fields' => array('username' => 'email')
));
...
}
So in your case I would do the following in the AppController:
function beforeFilter() {
parent::beforeFilter();
if($this->request->data['role'] == 2){
$this->Auth->authenticate = 'Special';
echo 'Method changed!';
} else {
$this->Auth->authenticate = 'Default';
}
...
}
... and in the components declaration only write:
public $components = array('RequestHandler', 'Session', 'Auth');
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
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'));
}
UserController
public function profile()
{
$this->set('profile', $this->User->find('all'));
}
profile.ctp
<?php
echo $profile['User']['name']; // Where user is the model and name is the name field in db.
?>
I know i am doing something wrong but i could not find any good solution for it.
public function profile(){
$this->set('current_user', $this->Auth->user());
}
public function profile()
{
$this->set('profile', CakeSession::read('Auth.User'));
}
Try this:
public function profile()
{
$user = $this->Auth->user();
$this->set('profile', $this->User->find('all',
array('conditions'=>array('User.id'=>$user['id']))));
}
You have to make a query.
You have already the User logged if you have
Auth
in your Appcontroller in $components like:
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email')
)
)
),
);
In your controller now you have the variable with the authenticated user in this mode:
$this->Session->read('Auth.User.id'));
You can make a query like this to retrieve in your database the record of the logged user:
this->set('profile', $this->User->find('all', array('recursive' => 1,
'conditions' => array('User.id' => $this->Auth->user()))));
What actually i did in my controller is
public function profile()
{
$id=$this->Session->read('Auth.User.id');
$this->set('profile', $this->User->findByid($id));
}
and its working :). Thank you all for clearing the logic.
I have tried most if not all tutorials for CakePHP 1.3 on their Auth method and non seem to work on CakePHP 2.0.
I can add users, hash the passwords, but the login feature does not work. It just refreshes the page when I click on login. No errors, no nothing.
I would appreciate some tips please and thank you for reading my question.
This my code
public function login()
{
if ($this->request->is('post') )
{
if( $this->Auth->login() )
{
// the redirect() function in the Auth class redirects us
// to the url we set up in the AppController.
return $this->redirect( $this->Auth->redirect());
}
else
{
$this->Session->setFlash(__('Email or password is incorrect',true));
}
}
}
Thanks,
Mahadeva Prasad
First of all check how you have hash the password.Also check the field length in database.
Preferred - varchar(255)
The password will be hash as follows.
class User extends AppModel {
public function beforeSave($options = array()) {
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
return true;
}
}
Also as you are using FormAuthenticate try using this when declaring component.
public $components = array(
'Auth' => array(
'loginAction' => array(
'controller' => 'users',
'action' => 'login',
),
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'username')
)
)
)
);
For more information refer http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
The web app is working great except for auth manual calls. I've been struggling with this for days. In my sample code I have temporarily rewritten the cookie to narrow down the cause. Here is my app controller snip:
App::import('Sanitize');
//uses('sanitize');
class AppController extends Controller {
var $components = array('Clean','Acl', 'Auth', 'Session', 'RequestHandler', 'Cookie', /* 'DebugKit.Toolbar' */);
var $helpers = array('uiNav','Flash','Html', 'Form', 'Session','Javascript','Ajax','Js' => array('Jquery'), 'Time','Js');
function beforeFilter() {
//Configure AuthComponent
$this->Auth->authorize = 'actions';
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'view');
$this->Auth->actionPath = 'controllers/';
$this->Auth->autoRedirect = false;
$this->Auth->allowedActions = array('display');
if(!$this->Auth->user()){
//$cookie = $this->Cookie->read('Auth.User');
$cookie = array('username' => 'chris22', 'password' => 'stuff');
if (!is_null($cookie)) {
$this->set('checking_cookie',$cookie);
if ($this->Auth->login($cookie)) {
$this->set('cookie_message','cookie validates!');
// Clear auth message, just in case we use it.
$this->Session->delete('Message.auth');
/* $this->redirect($this->Auth->redirect()); */
}
}
}
}
}
As you can see I'm just plugging the user name and password into $this->Auth->login and it's not working!!
I don't know if my user controller is relevent, but here is the login function for that too:
function login() {
if ($this->Auth->user()) {
if (!empty($this->data) && $this->data['User']['remember_me'] && isset($this->data['User']['password'])) {
$cookie = array();
$cookie['username'] = $this->data['User']['username'];
$cookie['password'] = $this->data['User']['password'];
$this->Cookie->write('Auth.User', $cookie, true, '+1 month');
//unset($this->data['User']['remember_me']);
$this->set('cookie-00', 'setting cookie.');
}else{ $this->set('cookie_message', 'not setting cookie.');}
$this->redirect($this->Auth->redirect());
}
}
Thanks!
EDIT - 1 - I think I know why this is not working for you.
Reason 1: $this->Auth->login takes data in the form of
array(
'User'=>array(
'username'=>'myusername',
'password'=>'mypassword'
)
)
Reason 2: $this->Auth->login does NOT hash the password.
You must send the password exactly as it appears in the database.
EVERYTHING BELOW THIS LINE IS POSSIBLE BUT NOT LIKELY IN THIS CASE:
Are you sure that when you originally created the username and password, the hashes were setup?
To check that your hashes match look at your users table with phpmyadmin or mysql workbench and find the password field for the user chris22
Compare that entry to your current hashing. To check your current hash, put the code below somewhere in a controller function (index) and navigate there.
debug(Security::hash('stuff'));
exit;
I hope this helps!
Make sure the fields are correctly assigned in the Auth component.
if you use different field names than username & password to connect, you must declare them in your controller like this way :
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email', 'password' => 'mot_de_passe')
)
)
)