I am wrestling with CakePHP trying to create a basic login functionality. So far CakePHP is winning. I followed the basic Blog tutorial and based on that I am try to create a similair login thingy.
The only difference I have is that I not using an Users model, but a custom Employers model and I use email/password instead of username/password.
Yet all I get is "Your username or password was incorrect."
AppController.php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'schedules',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'employers',
'action' => 'login',
'home'
),
'authenticate' => array(
'Form' => array(
'fields' => array(
'username' => 'email',
'password' => 'password'
),
'userModel' => 'Employer',
'passwordHasher' => 'Blowfish'
)
)
)
);
}
EmployersController.php
<?php
App::uses('AppController', 'Controller');
class EmployersController extends AppController {
public $helpers = array('Form');
public function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow('login');
}
public function login()
{
$layout = 'login';
$this->layout = $layout;
if($this->request->is('post'))
{
debug($this->Auth->login());
if($this->Auth->login())
{
return $this->redirect($this->Auth->redirect());
}
else
{
$this->Session->setFlash('Your username or password was incorrect.');
}
debug($this->request->data['Employers']['password']);
}
}
}
Login.ctp
<div id="login-container">
<h1>Login</h1>
<?php
echo $this->Form->create('Employers');
echo $this->Form->input('email', array('label' => false, 'placeholder' => 'Email'));
echo $this->Form->input('password', array('label' => false, 'placeholder' => 'Password'));
echo $this->Form->submit();
echo $this->Form->end();
?>
When I debug $this->request->data, the data is structered like data["Employers"]['email'] & data["Employers"]['password']. This is propably not right, since my model is called Employer.
Is this correct and does the login functionality break on this and if so, how can I fix that?
Or is there something else I am overlooking.
In your login.ctp,
It should be echo $this->Form->create('Employer'); not with s, so remove s and try it.
Hope it helps.
Related
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've tried every simple cakedc search setup, and followed code samples from previous posts on this but it just won't seem to cooperate for me. I'm not sure, but there doesn't seem to be any search query generated with the search string, judging from a query log I have running on my database.
When I try to search, from /books/search, I get no results on a title I know is in the database and the URL changes to /books/index/title:sweet (I'm not sure if that is relevant).
Any help would be much appreciated.
Model
public $actsAs = array('Search.Searchable');
public $primaryKey = 'isbn13';
public $hasMany = array(
'Contributor' => array (
'className' => 'Contributor',
'foreignKey' => 'isbn13'
),
'Override' => array (
'className' => 'Override',
'foreignKey' => 'isbn13'
)
);
public $filterArgs = array(
'title' => array('type' => 'query', 'method' => 'filterTitle'),
'main_desc' => array('type' => 'value')
);
public function filterTitle($data, $field = null) {
if (empty($data['title'])) {
return array();
}
$titleField = '%' . $data['title'] . '%';
return array(
'OR' => array(
$this->alias . '.title LIKE' => $titleField,
));
}
Controller
class BooksController extends AppController {
public $helpers = array ('Html', 'Form');
public $paginate = array();
public $components = array('Search.Prg');
public $presetVars = true;
public function index() {
//get books
$this->set('books', $this->Book->find('all'));
//search
/* $this->Prg->commonProcess();
$this->paginate['conditions'] = $this->Book->parseCriteria($this->Prg->parsedParams());
$this->set('books');
*/
}
public function search($books = NULL) {
$this->Prg->commonProcess();
$this->paginate['conditions'] = $this->Book->parseCriteria($this->passedArgs);
$this->set('books', $this->paginate());
}
View
<h1>Search Results</h1>
<?php
echo $this->Form->create('Book' , array(
'url' => array_merge(array('action' => 'search'), $this->params['pass'])
));
echo $this->Form->input('title', array('div' => false, 'empty' => true)); // empty creates blank option.
echo $this->Form->submit(__('Search', true), array('div' => false));
echo $this->Form->end();
Routes
Router::connect('/', array('controller' => 'books', 'action' => 'index'));
Router::connect('/index/*', array('controller' => 'books', 'action' => 'search'
));
Router::connect('/view/:url', array('controller' => 'books', 'action' => 'view', array('url' => '[\w\W]*')
));
Router::connect('/edit/:url', array('controller' => 'books', 'action' => 'edit', array('url' => '[\w\W]*')
));
Router::connect('/whatsnew/*', array('controller' => 'books', 'action' => 'whatsnew'
));
Router::connect('/search/*', array('controller' => 'books', 'action' => 'search'
));
I've renamed the search-master folder to Search and put it in my plugins directory and In my bootstrap.php I've loaded the plugin
CakePlugin::load('Search');
Fixed! Needed
$this->set('books', $this->paginate($this->Book->parseCriteria($this->passedArgs)));'
instead of
$this->set('books', $this->paginate());'
in the controller. Not sure why though..
In my present system I need to login using username or email and password.
can anybody knows how to achieve this ?
My Form:
<?php echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->input('username', array('class' => 'TextField js-user-mode'));
echo $this->Form->input('password', array('class' => 'TextField'));
?>
MY AppController:
public $components = array(
'Email'=>array(),
'Auth' => array(
'loginAction' => array(
'admin' => false,
'controller' => 'users',
'action' => 'login'
),
'authError' => 'Your session has ended due to inactivity. Please login to continue.',
'authenticate' => array(
'Form' => array(
'fields' => array('username' => array('username','email')),
),
'all' => array(
'userModel' => 'User',
'scope' => array('User.status' =>array('active'))
)
)
)
);
Let me know what else i need to do..??
I'm not sure what the etiquette is on posting answers to old questions but here's what I did for this.
In my login function
$username = $this->data['User']['username'];
$password = $this->request->data['User']['password'];
$user = $this->User->findByUsername($username);
if (empty($user)) {
$user = $this->User->findByEmail($username);
if (empty($user)) {
$this->Session->setFlash(__('Incorrect Email/Username or Password'));
return;
}
$this->request->data['User']['username'] = $user['User']['username'];
}
I found following code from this url. I think this is the best in sense of simplicity. Use following code on your login action:
public function login() {
if($this->request->is('post')&&!empty($this->request->data)) {
App::Import('Utility', 'Validation');
if( isset($this->data['User']['username']) && Validation::email($this->request->data['User']['username'])) {
$this->request->data['User']['email'] = $this->request->data['User']['username'];
$this->Auth->authenticate['Form'] = array('fields' => array('username' => 'email'));
}
if($this->Auth->login()) {
/* login successful */
$this->redirect($this->Auth->redirect());
} else {
/* login unsuccessful */
}
}
}
And also use following code for login.ctp :
<?php
echo $this->form->create('User');
echo $this->form->input('username');
echo $this->form->input('password');
echo $this->form->end('Submit');
?>
Simply we can do this before your Auth login action:
$emailUsername = #$this->request->data['User']['email'];
if (!filter_var($emailUsername, FILTER_VALIDATE_EMAIL)) {
$emailFromUsername = $this->User->find('first', array('conditions' => array('User.username' => $emailUsername), 'recursive' => -1, 'fields' => array('email')));
//pr($emailFromUsername );
if (!empty($emailFromUsername)) {
$emailFromUsernameDB = $emailFromUsername['User']['email'];
} else {
$emailFromUsername = '';
}
$this->request->data['User']['email'] = $emailFromUsername;
}
Assuming you have username and email both fields in your users table
In your AppController.php
public function beforeFilter() {
if ($this->request->is('post') && $this->action == 'login') {
$username = $this->request->data['User']['username'];
if (filter_var($username, FILTER_VALIDATE_EMAIL)) {
$this->Auth->authenticate['Form']['fields']['username'] = 'email';
$this->request->data['User']['email'] = $username;
unset($this->request->data['User']['username']);
}
}
}
This code will work for CakePHP 2.x, not tested on version 3.x, you should have email field in your user's table.
You can leverage the MultipleColumn Auth adapter:
https://github.com/ceeram/Authenticate/blob/master/Controller/Component/Auth/MultiColumnAuthenticate.php
Update:
New version # https://github.com/dereuromark/cakephp-tools/blob/master/src/Auth/MultiColumnAuthenticate.php
I found this solution useful.
I have created two classes that extend FormAuthenticate:
app/Controller/Component/Auth/ClassNameAuthenticate.php and
<?php
App::uses('FormAuthenticate', 'Controller/Component/Auth');
class ClassNameAuthenticate extends FormAuthenticate {
}
app/Controller/Component/Auth/ClassNameEmailAuthenticate.php
<?php
App::uses('FormAuthenticate', 'Controller/Component/Auth');
class ClassNameEmailAuthenticate extends FormAuthenticate {
}
then in my Controller added Auth Component to $components
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'ClassName' =>array(
'userModel'=>'ClassName',
'fields' => array(
'username' => 'username',
),
'scope' => array('ClassName.active' => 1)
),
'ClassNameEmail' =>array(
'userModel'=>'ClassName',
'fields' => array(
'username' => 'email',
),
'scope' => array('ClassName.active' => 1)
)
)
),
);
login view: login.ctp
<div class="form">
<?php echo $this->Form->create('ClassName'); ?>
<fieldset>
<legend><?php echo __('Login'); ?></legend>
<?php
echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(array('label'=>__('Login'))); ?>
</div>
and login() action:
public function login(){
if ($this->Auth->loggedIn()) {
return $this->redirect($this->Auth->redirect());
}
if ($this->request->is('post')) {
//Need to duplicate field email for ClassNameEmail Auth
$this->request->data['ClassName']['email'] = $this->request->data['ClassName']['username'];
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
}
$this->Session->setFlash(__('Invalid username/email or password, try again'));
}
}
I hope someone will find this useful.
this is my solution to solve that problem
public function login(){
if($this->request->is('post')){
$this->User->set($this->request->data);
if($this->User->validates()){
if(Validation::email($this->data['User']['username'])){
$this->Auth->authenticate['Form'] = array_merge($this->Auth->authenticate['Form'],array('fields'=>array('username'=>'email')));
$this->request->data['User']['email'] = $this->request->data['User']['username'];
unset($this->request->data['User']['username']);
}
if($this->Auth->login()){
$this->User->id = $this->Auth->user('id');
$this->User->saveField('last_login',time());
if($this->data['User']['remember']){
unset($this->request->data['User']['remember']);
$this->request->data['User']['password'] = Security::hash($this->request->data['User']['password'],'blowfish');
$this->Cookie->write('rememberMe',$this->request->data['User'],true,'2 days');
}
$this->redirect($this->Auth->loginRedirect);
}
$this->Session->setFlash('Invalid Username or Password entered, please try again.','default',array('class'=>'alert alert-warning'),'warning');
}
}
$this->set('title','Login Page');
}
I have tried to set up a login page, but when I try to log in, even with a wrong username/password, cake redirects to the login page (the logout function redirects correctly). Even if I plug in the wrong info, I get no error flashes at all, I don't get it. Here is my controller code:
class UsersController extends AppController {
public $name='Users';
public $layout='pagelayout';
public $uses=array('User');
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add', 'logout', 'overview');
}
public function login() {
$this->set('title', 'Log in to your Gulf Shores 4 Less account');
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
}
}
}
and here is my model:
<?php
App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {
public $name='User';
public $hasMany=array('Unit', 'Complex', 'Coupon', 'Location', 'Image', 'Charter', 'Course', 'Nightclub', 'Store');
public function beforeSave() {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
}
return true;
}
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A username is required'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'advertiser')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
)
);
}
?>
Here is the code from AppController:
<?php
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'users', 'action' => 'overview'),
'logoutRedirect' => array('controller' => 'pages', 'action' => 'index')
)
);
function beforeFilter() {
$this->Auth->allow('login','index', 'view', 'condos', 'houses', 'hotels_and_motels', 'print_all_coupons', 'print_coupon', 'search', 'golf', 'charters', 'events', 'nightlife', 'shopping', 'visitors_info', 'contact_us');
}
}
?>
and here is the view code:
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User');?>
<fieldset>
<legend><?php echo __('Please enter your username and password'); ?></legend>
<?php
echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(__('Login'));?>
</div>
As you can see, I pretty much copy and pasted what was in the Cakephp-2.0 manual for this. The only difference between my db table and the manual's is that my password is stored as an MD5 hash in my users table. i can't figure out where this has derailed.
Make sure that your passwords are stored using the Auth component hash. AFAIK, there is no support for 'plain' md5 passwords. The hashes Cake generates are more complex than md5.
See the documentation for info on how to hash your passwords. If you are migrating from an app that used md5 hashing, you'll have to reset all the passwords to something random for all your users.
You can try to use the following codes on your AppController.php file
AppController.php
$this->Auth->authenticate = array(
AuthComponent::ALL => array('userModel' => 'User'),
'Form' => array(
'fields' => array('username' => 'email')
)
);
$this->Auth->authorize =false;
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->fields = array('username' => 'email', 'password' => 'password');
$this->Auth->loginRedirect = array('controller' => 'media', 'action' => 'index/');
$this->Auth->logoutRedirect = '/logout';
$this->Auth->loginError = 'Invalid e-mail / password combination. Please try again';
This is a fairly long question but I have know idea where it's going wrong. I am making an ajax login script using CakePHP 2.0 but it keeps failing. I will post all of my code, and i hope someone has the time to go through it.
This is my sql Database
AccountID AccountEmail AccountPassword AccountActive
1 chris#hotmail.co.uk pass 0
2 chris#gmail.com pass 1
This is my relevant Model Code
class Account extends AppModel {
public $name = 'Account';
public $validate = array(
'AccountEmail' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'Please Enter A Valid Email.'
),
'email' => array(
'rule' => array('email', true),
'message' => 'Please supply a valid email address.'
)
),
'AccountPassword' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'Please Enter A Valid Password.'
)
)
);
}
This is my relevant Controller Code
class AppController extends Controller {
/**
* Class Variables
*/
public $helpers = array('Js', 'Html', 'Session', 'Form');
public $components = array(
'Session',
'RequestHandler',
'Auth' => array(
'logoutRedirect' => array(
'controller' => 'Accounts',
'action' => 'login'
),
'authError' => 'You can\'t Access That Page',
'authorize' => array('Controller'),
'authenticate' => array(
'Form' => array(
'fields' => array(
'username' => 'AccountEmail',
'password' => 'AccountPassword'
),
'scope' => array('AccountActive' => '1')
)
)
)
);
}
class AccountsController extends AppController {
/**
* Class Variables
*/
public $name = 'Accounts';
public $layout = 'Accounts';
/**
* Class Functions
*/
public function login()
{
if ($this->request->is('ajax')) {
$this->Account->set($this->data);
if ($this->Account->validates()) {
if($this->Auth->login()) {
echo "logged In";
exit;
} else {
echo "Login Failed";
exit;
}
} else {
echo 'validation/' . json_encode($this->Account->invalidFields());
exit;
}
}
}
I don't think there is anything else. Again i'm sorry for the huge amount of code but i just don't know what you need.
The info is all passed via 'echo' to jquery which at the moment is just displaying the response via 'alert'.
I know the validation is working, but if i enter the info of someone who should be able to login it just shows "Login Failed". Thanks For Your Time.
Your passwords in the database need to be in their hashed form. Using Cake's default settings, 'pass' would be: 1c31af5bd9913ff511fe780f506e6fab68979b90