I'm facing trouble with my login system. I managed to register my user in my database but whenever I try to log in, it keeps prompting "Invalid email or password, try again".
This is my model:
<?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('email', 'A email is required')
->add('email', 'valid' , ['rule'=> 'email'])
->add('email', [
'unique' => ['rule' => 'validateUnique', 'provider' => 'table']
])
->requirePresence('email','create')
->notEmpty('password', 'A password is required')
->notEmpty('role', 'A role is required')
->add('role', 'inList', [
'rule' => ['inList', ['admin', 'author']],
'message' => 'Please enter a valid role'
]);
}
}
My controller:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
use Cake\Network\Exception\NotFoundException;
class UsersController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow(['add', 'logout']);
}
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Invalid email or password, try again'));
}
}
public function logout()
{
return $this->redirect($this->Auth->logout());
}
public function index()
{
$this->set('users', $this->Users->find('all'));
}
public function view($id)
{
if (!$id) {
throw new NotFoundException(__('Invalid user'));
}
$user = $this->Users->get($id);
$this->set(compact('user'));
}
public function add()
{
$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' => 'add']);
}
$this->Flash->error(__('Email already existed.'));
}
$this->set('user', $user);
}
}
AppController:
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller
{
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'loginRedirect' => [
'controller' => 'Articles',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
public function isAuthorized($user)
{
if (isset($user['role']) && $user['role'] === 'admin') {
return true;
}
return false;
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'view', 'display']);
}
}
login.ctp
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('email') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
I think the problem comes from the AppController
Have a quick look at this : CookBook CakePHP 3.0 Example Bookmarker Part 1
The login part is here : CookBook CakePHP 3.0 Example Bookmarker Part 2
Find the similarities with your project, try to make an analogy, a relation.
Thanks guys! Managed to find the answer after referring to the tutorials. Turns out i miss out
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
All good now! Cheers =)
Related
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'
]);
}
}
}
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?
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)
I baked a cakephp application with a users table, and I'm trying to get authentication to work using the Blowfish hash. My password field is a varchar(255), so it should be long enough to store the hash. Everything in the app is the default baked output, expect for what follows.
This issue is that I can't log in after creating a user; I always get "Access Denied". What's the best way of troubleshooting this?
AppController.php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public function beforeFilter(){
$this->Auth->allow('index', 'view');
}
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email'),
'passwordHasher' => 'Blowfish'
)
),
'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'index'),
'authError' => "Access Denied",
'authorize' => array('Controller'),
)
);
public function isAuthorized($user){
return true;
}
}
User.php (model)
App::uses('AppModel', 'Model');
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
public function beforeSave($options = array()) {
if (!empty($this->data['User']['password'])) {
$passwordHasher = new BlowfishPasswordHasher();
$this->data['User']['password'] = $passwordHasher->hash($this->data['User']['password']);
}
return true;
}
UsersController.php
public function login(){
if ($this->request->is('post')) {
if($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
}
else {
$this->Session->setFlash('Access Denied');
}
}
}
login.ctp
echo $this->Form->create('user');
echo $this->Form->input('email');
echo $this->Form->input('password');
echo $this->Form->button('Log In', array('type' => 'submit');
echo $this->Form->end();
'debug($this->request); die;' in login function gives the following output. should password be * or should it be the hashed version of the input?
data => array(
'user' => array(
'password' => '*****',
'email' => 'test#test.com'
)
)
1)listen to #waspinator echo $this->Form->create('User');
2)
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
remove it ad put it in AppController and it should be
App::uses('AuthComponent', 'Controller/Component');
3)comment this lines
//public function beforeFilter(){
// $this->Auth->allow('index', 'view');
//}
//public function isAuthorized($user){
// return true;
//}
4) for first time put this on top of user controller so you can save your password
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('edit', 'index', 'view);
}
echo $this->Form->create('user');
should be
echo $this->Form->create('User');
I have a simple login form, just like the Cake Blog Tutorial.
It works like a charm when I use 'UsersController' and 'User' model naming conventions, passing the rights queries in debug.
But when I change it to other name, Alunos in my case, it generates no QUERY and give me 'Incorrect username and/or password.'.
My login.ctp
<H1> Login </H1>
<?php
debug($this->data);
echo $this->Form->create('Aluno', array('action' => 'login'));
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->end('Login');
?>
My AppController
<?php
class AppController extends Controller {
public $components = array (
'Session',
'Auth' => array (
'loginAction' => array ('controller'=>'alunos', 'action'=>'login'),
'loginRedirect'=>array ('controller'=>'alunos', 'action'=>'inicio'),
'logoutRedirect'=>array ('controller'=>'alunos', 'action'=>'index'),
'authError'=>"Ops, você não está autorizado a fazer isso.",
'authorize'=>array('Controller'),
)
);
public function isAuthorized($user) {
return true;
}
public function beforeFilter() {
$this->Auth->allow('index', 'add');
$this->set('logged_in', $this->Auth->loggedIn());
$this->set('current_user', $this->Auth->user());
}
}
And my 'AlunosController.php' (see that its not USERSController, like common codes)
<?php
class AlunosController extends AppController {
public $name = 'Alunos';
public function beforeFilter(){
parent::beforeFilter();
}
public function index() {}
public function login(){
debug($this->Auth->login());
if ($this->request->is('post')) {
if ($this->Auth->login()){
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Incorrect username and/or password.');
}
}
}
public function logout() {
$this->redirect($this->Auth->logout());
}
public function add() {
debug($this->Auth->login());
if($this->request->is('post')) {
if ($this->Aluno->save($this->request->data)) {
$this->Session->setFlash('Cadastrado.');
}else {
$this->Session->setFlash('Falha no cadastro.');
}
}
}
public function inicio() {
debug($this->Auth->login());
}
}
?>
My debug($this->data) in login.ctp result:
array(
'Aluno' => array(
'password' => '*****',
'username' => 'anyuser'
)
)
What am I doing wrong?
Add this code to your app controller:
function beforeFilter() {
$this->Auth->userModel = 'Aluno'; <-- Should be singular. My mistake
parent::beforeFilter();
}
UPDATE FOR CAKE2
// Place in beforeFilter() of AppController.php
$this->Auth->authenticate = array(
'Form' => array(
'userModel' => 'Aluno'
)
);
Your problem is because you are not telling cake what to use for a user table. This is why your first instance works, and the second does not.
Change this:
echo $this->Form->create('Aluno', array('action' => 'login'));
to:
echo $this->Form->create('Alunos', array('url' => 'alunos/login'));
To call Alunos Controller's login() method.