CakePHP validator rules in UsersTable.php wont work - cakephp

I'm creating a change password form in CakePHP, which requires that a user enter his/her current password, new password, and confirm new password. After all that is entered, the user's password will be changed, given that all entries follow the validation rules that are set.
However, the validation rules aren't working. The user doesn't have to fill in all of the fields, set the new password to a certain length, make sure that the new password and confirm password fields match, etc. I cant seem to find out what the problem is.
I'll provide all of the relevant code below. Thanks :)
change_password.ctp (The view file)
<div class="users form large-9 medium-9 columns">
<?= $this->form->create() ?>
<fieldset>
<legend> <?= __('Change Password') ?> </legend>
<?= $this->Form->input('current_password', ['type' => 'password']) ?>
<?= $this->Form->input('new_password', ['type' => 'password']) ?>
<?= $this->Form->input('confirm_new_password', ['type' => 'password']) ?>
</fieldset>
<?= $this->Form->button(__('Save')) ?>
<?= $this->Form->end() ?>
</div>
changePassword() in UsersController
public function changePassword()
{
$user = $this->Users->get($this->Auth->user('id'));
if (!empty($this->request->data)) {
$user = $this->Users->patchEntity($user, [
'password' => $this->request->data['new_password'],
],
['validate' => 'password']
);
if ($this->Users->save($user)) {
$this->Flash->success('The password is successfully changed');
$this->redirect('/users');
} else {
$this->Flash->error('There was an error during the save!');
}
}
$this->set('user', $user);
}
validationPassword() in UsersTable (i.e The validation rules)
public function validationPassword(Validator $validator )
{
$validator
->add('current_password','custom',[
'rule'=> function($value, $context){
$user = $this->get($context['data']['id']);
if ($user) {
if ((new DefaultPasswordHasher)->check($value, $user->password)) {
return true;
}
}
return false;
},
'message'=>'Incorrect Password!',
])
->notEmpty('current_password');
$validator
->add('new_password', [
'length' => [
'rule' => ['minLength', 6],
'message' => 'The password must be at least 6 characters!',
]
])
->add('new_password',[
'match'=>[
'rule'=> ['compareWith','confirm_new_password'],
'message'=>'The passwords does not match!',
]
])
->notEmpty('new_password');
$validator
->add('confirm_new_password', [
'length' => [
'rule' => ['minLength', 6],
'message' => 'The password must be at least 6 characters!',
]
])
->add('confirm_new_password',[
'match'=>[
'rule'=> ['compareWith','new_password'],
'message'=>'The passwords does not match!',
]
])
->notEmpty('confirm_new_password');
return $validator;
}
EDIT: Added User.php file
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\Validation\Validator;
/**
* User Entity.
*
* #property int $id
* #property string $first_name
* #property string $last_name
* #property string $email
* #property string $username
* #property string $password
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* #var array
*/
protected $_accessible = [
'*' => true,
'id' => false,
];
/**
* Fields that are excluded from JSON an array versions of the entity.
*
* #var array
*/
protected $_hidden = [
'password'
];
protected function _setPassword($value) {
$hasher = new DefaultPasswordHasher();
return $hasher->hash($value);
}
}

You have validation rules for fields current_password, new_password and confirm_new_password but you are only setting the field password with patchEntity that's why this validators are not called.
public function changePassword()
{
...
$user = $this->Users->patchEntity($user, [
'password' => $this->request->data['new_password'], // There is no validator defined for the field 'password'
],
['validate' => 'password']
);
...
}
In your case you must change your code with
public function changePassword()
{
...
$user = $this->Users->patchEntity($user, [
'password' => $this->request->data['new_password'], // Your actual field in db
'current_password' => $this->request->data['current_password'], // Trigger validation rule current_password
'new_password' => $this->request->data['new_password'], // Trigger validation rule new_password
'confirm_new_password' => $this->request->data['new_password'], // Trigger validation rule confirm_new_password
],
['validate' => 'password']
);
...
}
In the view file you have also forgot to pass the entity as first parameter of Form::create()

Related

Cakephp 3.7.4 Auth hash password Not working

I am trying to implement auth login and register cakephp 3.7.4
I have used following code for UsersController add method
public function add()
{
$this->viewBuilder()->setLayout('login');
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$post = $this->request->getData();
$post['created'] = date('Y-m-d H:i:s');
$post['modified'] = date('Y-m-d H:i:s');
$user = $this->Users->patchEntity($user, $post);
if ($this->Users->save($user)) {
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'login']);
}
$this->Flash->error(__('Unable to add the user.'));
}
$this->set('user', $user);
}
But it can't save password in Hash Format
I have also create entity and used this function but it also not helped me
class User extends Entity
{
protected $_accessible = [
'email' => true,
'password' => true
];
protected $_hidden = [
'password'
];
protected function _setPassword($password){
return(new DefaultPasswordHasher)->hash($password);
}
}
I installed a fresh Cake 3.7.4 installation, baked a users table, users controller and users table/entity. The following code for the User Class successfully hashed the password before it is written to the database. Please compare it with your code.
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
class User extends Entity
{
protected $_accessible = [
'email' => true,
'password' => true,
'modified' => true,
'created' => true
];
protected $_hidden = [
'password'
];
protected function _setPassword($password)
{
return (new DefaultPasswordHasher())->hash($password);
}
}
Just use parenthesis around DefaultPasswordHaser():
return(new DefaultPasswordHasher())->hash($password);

CakePHP: Validate login form

I need to validate a login form but I get error on form: Notice (8): Undefined variable: user [APP/Template\Users\login.ctp, line 5]
What could be?
login.ctp:
<br>
<div class="index large-4 medium-5 large-offset-4 medium-offset-4 columns">
<div class="panel">
<h2 class="text-center">Login</h2>
<?= $this->Form->create($user); ?>
<?= $this->Form->input('email' ,array('id' =>'email')); ?>
<?= $this->Form->input('password', array('type' => 'password'), array('id' => 'password')); ?>
<?= $this->Form->submit('Login', array('class' => 'button')); ?>
<?= $this->Form->end(); ?>
</div>
</div>
login function on UsersController.php:
public function login()
{
if($this->request->is('post'))
{
$user = $this->Auth->identify();
if($user)
{
$this->Auth->setUser($user);
return $this->redirect(['controller' => 'comentario']);
}
// Erro no Login
$this->Flash->error('Erro de autenticação');
}
}
UPDATE login function located in UsersController.php
public function login()
{
$user = $this->Auth->identify();
if($this->request->is('post'))
{
if($user)
{
$this->Auth->setUser($user);
return $this->redirect(['controller' => 'comentario']);
}
// Erro no Login
$this->Flash->error('Erro de autenticação');
}
}
Auth Configuration:
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
]
]);
}
$user is a reference to a variable and is undefined in your view. If you are creating a form for users, then the standard convention would be :
<?= $this->Form->create('User'); ?>
which will implicitly post to the same action that rendered the view.
Update:
You are calling auth for the $user before you check if the form is posted, so it will throw an undefined error before the form is submitted, when the view is rendered normally. I'm not overly familiar with 3.x, so you may or may not need to explicitly pass $this->request->data to the auth function. The method should be something like the following:
public function login()
{
if($this->request->is('post'))
{
$user = $this->Auth->identify();
if($user)
{
$this->Auth->setUser($user);
return $this->redirect(['controller' => 'comentario']);
}
// Erro no Login
$this->Flash->error('Erro de autenticação');
}
else{
//do something else here
}
}
From the 3.x documentation
Identifying Users and Logging Them In AuthComponent::identify() You
need to manually call $this->Auth->identify() to identify the user
using credentials provided in request. Then use $this->Auth->setUser()
to log the user in, i.e., save user info to session.
When authenticating users, attached authentication objects are checked
in the order they are attached. Once one of the objects can identify
the user, no other objects are checked. A sample login function for
working with a login form could look like:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Flash->error(__('Username or password is incorrect'), [
'key' => 'auth'
]);
}
}
}

Applying sessions in cakephp 3.2

Im using cakephp 3.2 to build an application. Im using the bookmarks tutorial as a basis for my project. in one of my bookmarks .ctp view files I would like to have a number of select boxes with data specific to the user loggged in. i have two tables namely users and bookmarks. My bookmarks table contains foreign key from users table user_id.
Here's my bookmark table with the fields i would like the dropdowns. id, user_id, title, systemregistration, systemroles, country, province, metropolitan.
Code for my appcontroller
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
/**
* Application Controller
*
* Add your application-wide methods in the class below, your controllers
* will inherit them.
*
* #link http://book.cakephp.org/3.0/en/controllers.html#the-app-controller
*/
class AppController extends Controller
{
/**
* Initialization hook method.
*
* Use this method to add common initialization code like loading components.
*
* e.g. `$this->loadComponent('Security');`
*
* #return void
*/
/*public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
}*/
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
//'storage' => 'Session'
'Session'
]);
// Allow the display action so our pages controller
// continues to work.
$this->Auth->allow(['display']);
}
/*public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Bookmarks',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'view', 'display']);
}*/
/**
* Before render callback.
*
* #param \Cake\Event\Event $event The beforeRender event.
* #return void
*/
public function beforeRender(Event $event)
{
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
}
}
}
//BookmarksController looks like this
namespace App\Controller;
use App\Controller\AppController;
/**
* Bookmarks Controller
*
* #property \App\Model\Table\BookmarksTable $Bookmarks
*/
class BookmarksController extends AppController
{
public function internalprotocol()
{
$bookmark = $this->Bookmarks->newEntity();
$users = $this->Bookmarks->Users->find('list', ['limit' => 200]);
$tags = $this->Bookmarks->Tags->find('list', ['limit' => 200]);
$this->set(compact('bookmark', 'users', 'tags'));
$this->set('_serialize', ['bookmark']);
$bookmarks = $this->paginate($this->Bookmarks);
$this->set(compact('bookmarks'));
$this->set('_serialize', ['bookmarks']);
}
}
//my internalprotocol.ctp looks like this
<div>
<?php echo $this->Form->input('user_id', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('title', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('systemregistration', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('systemroles', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('country', ['options' => $bookmarks]); ?>
</div>
I would like to populate each of the fields with data specific to the user logged in. Could you please help!
You don't need to do anything. If a login is successful you can access the logged in user details through the Auth component using $this->Auth->user();
If you need to add any more information to the session you can use the Session component like $this->Session->write('User.AscociatedData', $AscociatedData);
Easiest way to access this data in the view is to set authenticated user as a view variable in the controller:
$this->set('user',$this->Auth->user());
then you can accesses the users info in the view with $user e.g$user->fieldName
Not entirely sure what your asking but I hope one of my answers is relevant.
we only need to show bookmarks for the currently logged in user.
We can do that by updating the call to paginate().Make your index() action from Controller/BookmarksController.php look like:
public function index()
{
$this->paginate = [
'conditions' => [
'Bookmarks.user_id' => $this->Auth->user('id'),
]
];
$this->set('bookmarks', $this->paginate($this->Bookmarks));
$this->set('_serialize', ['bookmarks']);
}
We should also update the tags() action and the related finder method as we done for bookmarks above
Please read the tutorial
http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/part-two.html#fixing-list-view-and-forms

Unknown method "allow"

So I have this controller and method:
Contorller/UsersController.php
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
use Cake\Network\Exception\NotFoundException;
use Cake\ORM\TableRegistry;
/**
* Jobs Controller
*
* #property \App\Model\Table\JobsTable $Jobs
*/
class UsersController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Users->allow('register');
}
public function register()
{
//Get Categories
$getCategories = TableRegistry::get('Categories');
$categories = $getCategories->find('all');
$this->set('categories',$categories);
$this->set('title', 'Registration');
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->data);
if ($this->Users->save($user)) {
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'register']);
}
$this->Flash->error(__('Unable to add the user.'));
}
$this->set('user', $user);
}
}
Model/Table/UsersTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class UsersTable extends Table
{
public function validationDefault(Validator $validator)
{
return $validator
->notEmpty('first_name', 'A username is required')
->notEmpty('last_name', 'A username is required')
->notEmpty('email', 'A username is required')
->notEmpty('username', 'A username is required')
->notEmpty('password', 'A username is required')
->add('role', 'inList', [
'rule' => ['inList', ['Employer', 'Job Seeker']],
'message' => 'Please enter a valid role'
]);
}
}
?>
Template/Users/register.ctp:
<div class="users form">
<?php echo $this->Form->create($user); ?>
<fieldset>
<legend><?= __('Create New User'); ?></legend>
<?php
echo $this->Form->input('first_name');
echo $this->Form->input('last_name');
echo $this->Form->input('email',array('type'=>'email'));
echo $this->Form->input('username');
echo $this->Form->input('password',array('type'=>'password'));
echo $this->Form->input('confirm_password',array('type'=>'password'));
echo $this->Form->input('role',array(
'type' => 'select',
'options' => ['Employer'=>'Employer','Job Seeker'=>'Job Seeker'],
'empty' => 'Select Role'
));
?>
</fieldset>
<?= $this->Form->button(__('Submit')); ?>
<?= $this->Form->end() ?>
</div>
Entity/User.php:
<?php
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
/**
* User Entity.
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* #var array
*/
protected $_accessible = array(
'first_name' => true,
'last_name' => true,
'email' => true,
'username' => true,
'password' => true,
'role' => true,
'created' => true
);
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
}
So when I'm trying to access /users/register view, it gives me next error:
Unknown method "allow": $this->Users->allow('register');
But if I remove next method inside of my Users controller:
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Users->allow('register');
}
It works fine, but I guess it also must work with it as well. So what am I doing wrong or missing?

Users Authentication fail

So this is my login method:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Flash->error(__('Invalid username or password, try again'));
}
}
}
And this is how I has my password inside my User entity:
<?php
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
/**
* User Entity.
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* #var array
*/
protected $_accessible = array(
'first_name' => true,
'last_name' => true,
'email' => true,
'username' => true,
'password' => true,
'role' => true,
'created' => true
);
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
}
I already have working user registration and it's working without problems(password is being hashed), but for some reason I can't login, it always says that
Invalid username or password, try again
But those are present in my table, here is the query:
SELECT
Users.id AS `Users__id`,
Users.first_name AS `Users__first_name`,
Users.last_name AS `Users__last_name`,
Users.email AS `Users__email`,
Users.username AS `Users__username`,
Users.password AS `Users__password`,
Users.role AS `Users__role`,
Users.created AS `Users__created`
FROM
users Users
WHERE
Users.username = 'admin' LIMIT 1
But for some reason it does nothing in my app. I guess something is wrong with the password?
Form:
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
AppController:
class AppController extends Controller
{
/**
* Initialization hook method.
*
* Use this method to add common initialization code like loading components.
*
* #return void
*/
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Jobs',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Jobs',
'action' => 'index'
],
'authorize' => ['controller']
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'browse', 'view', 'register']);
}
}
Found the answer here:
Login [ Auth->identify() ] always false on CakePHP 3
Summary:
Table field password was VARCHAR(45) instead of VARCHAR(255)

Resources