Using CakePHP's Auth Component, how do I allow users to authenticate by using either their "username" or "email" field as a username, and a "pass" field as their password?
what does "using (username and email) both as username " mean?
Edit: ok, so you want Auth to look in both username and email fields in the db to compare to the "username" that the user enters? then do this:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->fields = array('username' => 'username', 'password' => 'pass');
$this->Auth->autoRedirect = false;
}
function login(){
if ($this->Auth->user()) {
$this->redirect($this->Auth->redirect());
} else if (!empty($this->data)) {
$this->Auth->fields = array('username' => 'email', 'password' => 'pass');
$this->data['User']['email'] = $this->data['User']['username'];
if($this->Auth->login($this->data))$this->redirect($this->Auth->redirect());
}
}
To do this you have to skip Auths autoredirect and manage it yourself. This the login action in your users_controller:
public function login() {
if(!empty($this->data)) { // Submitted form
// Try to login with Email
if(!$this->Auth->user() // if user wasn't logged in with username + pass
&& !empty($this->Auth->data['User']['username'])
&& !empty($this->Auth->data['User']['password'])
) {
$user = $this->User->find('first', array(
'conditions' => array(
'User.email' => $this->Auth->data['User']['username'],
'User.password' => $this->Auth->data['User']['password']
),
'recursive' => -1
));
if(!empty($user) && $this->Auth->login($user)) {
// They logged in, so kill the flash error message
$this->Session->delete('Message.auth');
} else {
$this->Session->setFlash($this->Auth->loginError, $this->Auth->flashElement, array(), 'auth');
}
}
if($this->Auth->user()) {
// Post login logic here
$this->redirect($this->Auth->redirect());
}
} else {
if($this->Auth->user()) {
$this->Session->setFlash(__d('users', 'You are already registered and logged in!', true));
//$this->redirect('/');
$this->redirect($this->Auth->redirect());
}
}
This was copied straight from my app, so may need a bit of tweaking for yours. Don't forget to set $this->Auth->autoRedirect = false; in your AppController:beforeFilter();
You have to remember that Auth will automatically check against username and password, so this action just picks up from that. The Session::remove() call is to delete the Auth error message automatically left when the username/password check fails ANd the email login succeeds (otherwise you get error messages with successful logins).
Related
I am new in cake php.
I am using cakephp 3.6.2 in linux ubuntu.
I use cakephp auth component.
While i give correct credentials it redirect back to the login page otherwise says error message "invalid username and password".
I debug and check details while i give correct credentials. It Set " $this->Auth->setUser($user);" correctly.
But After redirect " return $this->redirect($this->Auth->redirectUrl());"
$this->Auth->User() is Null and it redirects back to login page.
My Code
AppController.php
public function initialize(){
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email', 'password' => 'password']
]
],
'loginAction' => ['controller' => 'Users', 'action' => 'login']
]);}
UserCOntroller.php
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
debug($this->Auth->User()); //contain user details correctly
debug($this->redirect($this->Auth->redirectUrl())); // //contain userdetails correctly
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Invalid username or password, try again'));
}
}
public function logout()
{
return $this->redirect($this->Auth->logout());
}
User.php
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
I print phpinfo() session is enabled. other projects under the "var/www/html" working properly. But inside this project only session not working.
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.
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')
),
)
),
);
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 have a user front end and an admin area. If a user is signed in and trys to go to the to the admin url they are redirected to the index page. I wish to redirect them to the admin login page with a message to login as administrator.
There may be a case where a admin is logged in as a user and then trys to login into the admin area. I have not been able to rediect to the admin login and give option to log out and log in as admin.
app_controller
function beforeFilter() {
$this->Auth->loginError = "Wrong credentials";
$this->Auth->authError = "This part of the website is protected.";
//Configure AuthComponent
$this->Auth->allow('display');
$this->Auth->authorize = 'actions';
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
//$this->Auth->autoRedirect = false;
//$this->Auth->loginRedirect = array('controller' => 'reservatins', 'action' => 'index');
} // end before filter
users_controller
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allowedActions = array('admin_login','admin_logout');
//$this->Auth->allowedActions = array('*');
$this->set('select_nav', array('admin','users'));
}
function admin_login() {
// $this->layout = 'admin'; // nothing required
$this->layout = 'blank'; // nothing required
}
I have done that on one of my projects. The user is ever logged in (as Anonymous, as User or as Admin) and, depending on from where is he coming, and the current permissions he have, I show different login errors.
To do that.. this is what I did...
First, you need to use the "controller" authorize method:
$this->Auth->authorize = 'controller';
From now on, all your actions will pass through the isAuthorized method of your current controller. As I have my users, groups and permissions on my database and every group have different permissions, I created the isAuthorized method on my app_controller:
public function isAuthorized()
{
if ( !$this->__permitted($this->name, $this->action) )
{
$this->cakeError('error403');
return false;
}
return true;
}
What I'm doing here is checking for user permissions through my AppController __permitted method (it simply checks for permissions on session; if we don't have them saved in session, I check for them on the DB and then I store them on the Session).
If the user don't have permissions, I show him the error 403. And here is the funny part.
In your AppError add a method called error403, and here you can control where to redirect the user and what kind of message to show to him.
Here is the code I've used (obviously you must create your own piece of code according to your needs):
public function error403()
{
// Extract params
extract($this->controller->params, EXTR_OVERWRITE);
// Store url to be redirected on success
if (!isset($url))
{
$url = $this->controller->here;
}
if (isset($url['url']))
{
$url = $url['url'];
}
$url = Router::normalize($url);
// The page is trying to access is an admin page?
$is_admin_page = isset($this->controller->params['admin']) && $this->controller->params['admin'] == true ? true : false;
if (!empty($url) && count($url) >= 2)
{
$query = $url;
unset($query['url'], $query['ext']);
$url .= Router::queryString($query, array());
}
// 403 header
$this->controller->header("HTTP/1.0 403 Forbidden");
// If my method is NOT an upload
if (!preg_match('/upload/', $url))
{
// Write referer to session, so we can use it later
$this->controller->Session->write('Auth.redirect', $url);
}
else exit; // else exit, so we prevent 302 header from redirect
// NOTE: we can't use $this->controller->Auth->loginAction because there's no controller loaded
$loginAction = array('controller' => 'users', 'action' => 'login');
// If is ajax...
if (isset($this->controller->params['isAjax']) && $this->controller->params['isAjax'] == true)
{
$this->controller->layout = 'ajax';
$message = __("No tens permisos per fer aquesta acció", true);
// If user is anonymous..
if ( $this->controller->ISession->isAnonymous() )
{
// AJAX Error Message
$message = __('La teva sessió no està iniciada.', true)
. ' <a href="'.Router::url($loginAction).'">'
. __('Fes clic aquí per iniciar-la', true) . '</a>';
}
$this->controller->set(compact('message'));
$this->controller->render('error403');
$this->controller->afterFilter();
echo $this->controller->output;
}
else
{
$message = __("No tens permisos per fer aquesta acció", true);
$redirect = $this->controller->referer();
// If is anonymous...
if ($this->controller->ISession->isAnonymous())
{
$message = __('La teva sessió no està iniciada.', true);
$redirect = $loginAction;
}
// If user can't access the requested page, we redirect him to login
if (!$this->controller->ISession->userCan($redirect))
{
$redirect = $loginAction;
}
// Show different auth messages for admin and user pages
$this->controller->Session->setFlash($message, $is_admin_page ? 'default' : 'gritter', array(), 'auth');
$this->controller->redirect($redirect, null, true);
}
}
Remember, this is the code for my case. You should create your own error403 page according to your needs. Of course, you can start with my method to get it :)