I'm trying to understand how Cakephp works. I built a connection system with a simple form (username and password). When I click on the submit button (with the correct username and password), I always receive the same flash message, "Your username or password was incorrect". I tried many things, but I don't know how to fix it .
If I'm logged, I want to be redirect on Google (it's the test i try) .
Look at my code :
login.ctp (View)
<?php
echo $this->Form->create('User',array('action'=>'login'));
echo $this->Form->inputs(array('legend'=>'Se connecter','username','password'));
echo $this->Form->end('Se connecter');
?>
UsersController
class UsersController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow();
}
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$this->User->id = $this->Auth->user("id");
$this->redirect('http://www.google.fr');
} else {
$this->Session->setFlash('Your username or password was incorrect.');
}
}
}
}
User (Model)
<?php
App::uses('AppModel', 'Model', 'AuthComponent', 'Controller/Component');
class User extends AppModel {
public $actsAs = array('Acl' => array('type' => 'requester'));
public function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
if (isset($this->data['User']['group_id'])) {
$groupId = $this->data['User']['group_id'];
} else {
$groupId = $this->field('group_id');
}
if (!$groupId) {
return null;
} else {
return array('Group' => array('id' => $groupId));
}
}
public function beforeSave($options = array()) {
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
return true;
}
public $belongsTo = array(
'Group' => array(
'className' => 'Group',
'foreignKey' => 'group_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
?>
The password in my table user (sql) :
password char(40) latin1_swedish_ci
Related
Hi i'm quite new to yii framework, currently trying to establish a login through database authentication. but while im trying to log in i get this error saying
Please fix the following input errors:
Password is incorrect.
but when i check the database table im typing the correct password.
can anybody help me out if this
Heres the Controller
<?php
class SiteController extends Controller
{
public function actions()
{
return array(
'captcha'=>array(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
),
'page'=>array(
'class'=>'CViewAction',
),
);
}
public function actionIndex()
{
$this->render('index');
}
public function actionError()
{
if($error=Yii::app()->errorHandler->error)
{
if(Yii::app()->request->isAjaxRequest)
echo $error['message'];
else
$this->render('error', $error);
}
}
public function actionContact()
{
$model=new ContactForm;
if(isset($_POST['ContactForm']))
{
$model->attributes=$_POST['ContactForm'];
if($model->validate())
{
$name='=?UTF-8?B?'.base64_encode($model->name).'?=';
$subject='=?UTF-8?B?'.base64_encode($model->subject).'?=';
$headers="From: $name <{$model->email}>\r\n".
"Reply-To: {$model->email}\r\n".
"MIME-Version: 1.0\r\n".
"Content-Type: text/plain; charset=UTF-8";
mail(Yii::app()->params['adminEmail'],$subject,$model->body,$headers);
Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
$this->refresh();
}
}
$this->render('contact',array('model'=>$model));
}
public function actionLogin()
{
$form=new LoginForm;
if(isset($_POST['LoginForm']))
{
$form->attributes=$_POST['LoginForm'];
if($form->validate() && $form->login()) $this->redirect(Yii::app()->user->returnUrl);
}
$this->render('login',array('form'=>$form));
}
public function actionLogout()
{
Yii::app()->user->logout();
$this->redirect(Yii::app()->homeUrl);
}
}
herers the model
<?php
class LoginForm extends CFormModel
{
public $email;
public $password;
private $_identity;
public function rules()
{
return array(
array('email, password', 'required'),
array('email', 'email'),
array('password', 'authenticate'),
);
}
public function attributeLabels()
{
return array('email'=>'Email Address');
}
public function authenticate($attribute,$params)
{
if(!$this->hasErrors()) // we only want to authenticate when no input errors
{
$identity=new UserIdentity($this->email,$this->password);
$identity->authenticate();
switch($identity->errorCode)
{
case UserIdentity::ERROR_NONE:
Yii::app()->user->login($identity);
break;
case UserIdentity::ERROR_USERNAME_INVALID:
$this->addError('email','Email address is incorrect.');
break;
default: // UserIdentity::ERROR_PASSWORD_INVALID
$this->addError('password','Password is incorrect.');
break;
}
}
}
public function login()
{
if($this->_identity===null)
{
$this->_identity=new UserIdentity($this->username,$this->password);
$this->_identity->authenticate();
}
if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
{
$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->user->login($this->_identity,$duration);
return true;
}
else
return false;
}
}
here the view
<?php
/* #var $this SiteController */
/* #var $model LoginForm */
/* #var $form CActiveForm */
$this->pageTitle=Yii::app()->name . ' - Login';
$this->breadcrumbs=array(
'Login',
);
?>
<h1>Login</h1>
<p>Please fill out the following form with your login credentials:</p>
<div class="form">
<?php $myWidget=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<div>
<?php echo CHtml::beginForm(); ?>
<?php echo CHtml::errorSummary($form); ?>
<div>
<?php echo CHtml::activeLabel($form,'email'); ?>
<?php echo CHtml::activeTextField($form,'email') ?>
</div>
<div>
<?php echo CHtml::activeLabel($form,'password'); ?>
<?php echo CHtml::activePasswordField($form,'password') ?>
</div>
<div>
<?php echo CHtml::submitButton('Login'); ?>
</div>
<?php echo CHtml::endForm(); ?>
endWidget(); ?>
You have to write your authentication logic inside UserIdentity class not in LoginForm model.
LoginForm model ex:-
public function authenticate($attribute, $params) {
if (!$this->hasErrors()) {
$this->_identity = new UserIdentity($this->email, $this->password);
if (!$this->_identity->authenticate())
$this->addError('password', 'Incorrect username or password.');
}
}
public function login() {
if ($this->_identity === null) {
$this->_identity = new UserIdentity($this->email, $this->password);
$this->_identity->authenticate();
}
if ($this->_identity->errorCode === UserIdentity::ERROR_NONE) {
$duration = $this->rememberMe ? 3600 * 24 * 30 : 0; // 30 days
Yii::app()->user->login($this->_identity, $duration);
return true;
} else
return false;
}
For database authentication you must have to add your authetication logic inside authenticate function using components\UserIdentity.php
public function authenticate() {
Yii::app()->getModule('auth')->getModule('user'); #import your module.
$record = User::model()
->findByAttributes(array('email' => CHtml::encode($this->email))); #database call
if ($record === null)
$this->errorCode = self::ERROR_USERNAME_INVALID;
#else if ($record->password !== crypt($this->password, $record->password))
else if ($record->password !== $this->password)
$this->errorCode = self::ERROR_PASSWORD_INVALID;
else {
$this->_uid = $record->user_id;
$this->setState('title', $record->user_name);
$this->setState('uid', $this->_uid);
$this->errorCode = self::ERROR_NONE;
}
return !$this->errorCode;
}
If you have role based login then you have to add WebUser class in config/main.php.
components' => array(
'user' => array(
// enable cookie-based authentication
'class' => 'WebUser',
'allowAutoLogin' => true,
'loginUrl'=>array('/site/login'),
'returnUrl'=>array('/site/index'),
),
}
For role based assess check you have to write components\WebUser.php Class -
class WebUser extends CWebUser {
public function checkAccess($operation, $params = array()) {
if (empty($this->id)) {
// Not identified => no rights
return false;
}
$role = $this->getState("roles");
if ($role === '3') {
return true; // super admin role has access to everything
}else if ($role === '1') {
return true; // admin(manager) role has access to everything
}
// allow access if the operation request is the current user's role
return ($operation === $role);
}
}
For more information check Authentication and Authorization
In common/models/User.php
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_INACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE,
self::STATUS_INACTIVE, self::STATUS_DELETED]],
];
}
In this method, set the default 'value'=>self::STATUS_ACTIVE
your problem will be solved. I also had the same issue. After changing the value to Active, it worked, because the default value it is setting is 9 and the database considers it an inactive entry that's why it is shoeing incorrect id or password. I hope this helps.
I am developing the simple register form.And develope the model,controller,view classes.but i am unable to show the error messages in my application.
User.php(Model class)
<?php
class User extends AppModel
{
var $name='User';
public $validate= array(
'username'=>array(
'rule'=>'notEmpty',
'required'=>true,
'message'=>'Enter your name'
),
'email' => array(
'rule' => 'notEmpty',
'message' => 'Please enter your email'
)
);
}
?>
UsersController.php
<?php
class UsersController extends AppController {
public $helpers = array('Html', 'Form');
array('action' => 'edit')
public function register() {
if ($this->User->validates()) {
$this->User->set($this->request->data);
$name = $this->request->data['User']['username'];
$email = $this->request->data['User']['email'];
}
else{
$this->flash('register fail');
}
}
}
?>
register.ctp
<?php
echo $this->Form->create('User',array('action'=>'register'));
echo $this->Form->input('username');
echo $this->Form->input('email');
echo $this->Form->end('Register');
?>
when i am click the register button above code is not showing the error messages.
Finally i got the answer to my question. i.e
User.php
<?php
class User extends AppModel
{
public $validate= array(
'username'=>array(
'rule'=>'notEmpty',
'required'=>false,
'message'=>'Enter your name'
),
'email' => array(
'rule' => 'notEmpty',
'required'=>false,
'message' => 'Please enter your email'
)
);
}
?>
UsersController.php
<?php
class UsersController extends AppController {
public $helpers = array('Html', 'Form');
public function register() {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->redirect(array('controller'=>'users', 'action'=>'welcome'));
}
else{
echo"register fail";
}
}
public function welcome(){
$this->flash('register successfully','/users/register');
}
}
?>
register.ctp
<?php
echo $this->Form->create('User');
echo $this->Form->input('username',array('required'=>'false'));
echo $this->Form->input('email',array('required'=>'false'));
echo $this->Form->end('Register');
?>
this is the correct answer for above asking question.The main mistake done in my above question was i am given required'=>'true.',now given required'=>'false.' in register.ctp class.now problem resolved.
You need to change you register action in user controller like this:
public function register() {
$this->User->create();
if ($this->User->save($this->request->data)) { //this way it automatically save or show error message if there is one
$this->flash('register success');
}
else{
$this->flash('register fail');
}
}
Hope it helps.
Try this:
add a helper
var $helpers = 'session';
then add the flash message as
$this->Session->setFlash(__('error'));
What you actually want is to show the validation errors, so instead of
$this->flash('register fail');
Do
$this->Session->setflash($this->User->validationErrors);
$this->redirect('/users/register');
I am creating login action in the yii framework, but I have an error and I cannot fix it. Here is the error:
Property "AdminIdentity.user_name" is not defined. `$record=Admin::model()->findByAttributes(array('username'=>$this->user_name));`
This is my login module:
login.php
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login_form',
'enableAjaxValidation'=>false,
'enableClientValidation' => true));
?>
<div class="row">
<?php echo $form->labelEx($model,'username'); ?>
<?php echo $form->textField($model,'username',array('size'=>60,'maxlength'=>100)); ?>
<?php echo $form->error($model,'username'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'password'); ?>
<?php echo $form->passwordField($model,'password',array('size'=>60,'maxlength'=>100)); ?>
<?php echo $form->error($model,'password'); ?>
</div>
<div id="lower">
<?php echo $form->Checkbox($model,'rememberMe'); ?>
<?php echo $form->labelEx($model,'rememberMe'); ?>
<input type="submit" value="Login"/>
</div>
<?php $this->endWidget(); ?>
AdminController and actionLogin
class AdminController extends Controller
{
public function actionLogin()
{
$this->layout = 'login';
$model=new LoginForm;
if(isset($_POST['ajax']) && $_POST['ajax']==='login_form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
if($model->validate() && $model->login()){
$this->redirect('/ktbeauty/index.php/categories/index');
}
}
$this->render('login',array(
'model'=>$model,
));
}
}
LoginForm
class LoginForm extends CFormModel{
public $username;
public $password;
public $rememberMe;
private $_identity;
public function rules()
{
return array(
// username and password are required
array('username, password', 'required','message'=>'input username requirement'),
// rememberMe needs to be a boolean
array('rememberMe', 'boolean'),
// password needs to be authenticated
array('password', 'authenticate','required','message'=>'input password requirement'),
);
}
public function attributeLabels()
{
return array(
'username'=>'User Name',
'rememberMe'=>'Remember me next time',
'password'=>'Password',
);
}
public function authenticate($attribute,$params)
{
if(!$this->hasErrors())
{
$this->_identity=new AdminIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','Incorrect username or password.');
}
}
public function login()
{
if($this->_identity===null)
{
$this->_identity=new AdminIdentity($this->username,$this->password);
$this->_identity->authenticate();
}
if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
{
$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->admin->login($this->_identity,$duration);
return true;
}
else
return false;
}
}
AdminIdentity class:
class AdminIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{
$record=Admin::model()->findByAttributes(array('username'=>$this->user_name));
var_dump($record);exit;
if($record===null)
{
$this->_id='user Null';
$this->errorCode=self::ERROR_USERNAME_INVALID;
}
else if($record->password!==$this->password)
{
$this->_id=$this->user_name;
$this->errorCode=self::ERROR_PASSWORD_INVALID;
}
else if($record['user_active']!=='1')
{
$err = "You have been Inactive by Admin.";
$this->errorCode = $err;
}
else
{
$this->_id=$record['ad_id'];
$this->setState('user_name', $record['user_name']);
$this->errorCode=self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId()
{
return $this->_id;
}
}
Admin Model class:
class Admin extends CActiveRecord
{
public function tableName()
{
return 'admin';
}
public function rules()
{
return array(
array('user_status','length', 'max'=>1),
array('user_active','length', 'max'=>1),
array('user_name, password, email', 'length', 'max'=>100),
array('phone, cellphone, name', 'length', 'max'=>45),
array('ad_id, user_name, password, email, phone, cellphone, name, user_status, user_active', 'safe', 'on'=>'search'),
);
}
public function relations()
{
return array(
);
}
public function attributeLabels()
{
return array(
'ad_id' => 'Ad',
'user_name' => 'User Name',
'password' => 'Password',
'email' => 'Email',
'phone' => 'Phone',
'cellphone' => 'Cellphone',
'name' => 'Name',
'user_status' => 'User Status',
'user_active' => 'User Active',
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('ad_id',$this->ad_id);
$criteria->compare('user_name',$this->user_name,true);
$criteria->compare('password',$this->password,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('phone',$this->phone,true);
$criteria->compare('cellphone',$this->cellphone,true);
$criteria->compare('name',$this->name,true);
$criteria->compare('user_status',$this->user_status);
$criteria->compare('user_active',$this->user_active);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
class AdminIdentity extends CUserIdentity and in CUserIdentity there are 2 properties defined:
$username
$password
So you should either change
$record=Admin::model()->findByAttributes(array('username'=>$this->user_name));
to
$record=Admin::model()->findByAttributes(array('username'=>$this->username));
or
declare $user_name in your AdminIdentity class. If you choose to declare the new property make sure you set a value in the constructor (more changes will be needed)
I am using beforeSave() to assign the user a temporary customer number. I need to return this value to the device accessing the API. Is it possible to access that from my controller?
// app/Model/User.php
<?php
class User extends AppModel {
function beforeSave($options) {
$this->data['User']['customerNumber'] = uniqid(); // This is the value I want
$this->data['User']['password'] = md5($this->data['User']['password']);
}
function isUnique() {
$users = $this->find('all', array('conditions' => array('email' => $this->data['User']['email'])));
if (empty($users)) {
return true;
} else {
return false;
}
}
}
?>
// app/Controller/UserController.php
<?php
class UserController extends AppController {
public $components = array('RequestHandler');
public function register() {
if ($this->request->is('post')) {
$this->User->set($this->data);
if ($this->User->isUnique()) {
if ($this->User->save($this->data)) {
// This is where I need to return the customer number
echo json_encode(array('status' => 'User registered', 'customerNumber' => $this->data['customerNumber']));
} else {
echo json_encode(array('status' => 'User could not be registered'));
}
} else {
echo json_encode(array('status' => 'user is duplicate'));
}
} else {
echo json_encode(array('error' => 'Requests must be made using HTTP POST'));
}
}
}
?>
As a secondary question, is uniqid() an okay way to assign temporary customer numbers?
You can't get to that value directly, but you can immediately fetch it after a succesful save, like:
if ($this->User->save($this->data)) {
// Fetch inserted row
$user = $this->User->findById($this->User->getInsertId());
echo json_encode(array(
'status' => 'User registered',
'customerNumber' => $user['User']['customerNumber']
));
}
I'm writing a new application with CakePHP (just-released 1.2.4), using SimpleTest 1.0.1. I have read the relevant sections of the Cookbook, searched on the Bakery, and read Mark Story's postings on controller testing (the hard way and with mocks).
Unfortunately, none of this talks about real-world testing of non-trivial controllers. Lots of apps put areas of the site behind a login, yet I cannot figure out how to test the simple scenario of:
guest access to protected page redirects?
valid credentials sets expected session variables?
invalid credentials re-displays login page with error message?
The controller and test below do not work as I thought they would. Both assertions fail and I also get a PHP error:
FAILED
[NULL] should not be null at [.../app/tests/cases/controllers/users_controller.test.php line 79]
.../app/tests/cases/controllers/users_controller.test.php -> UsersControllerTest -> testLogin
FAILED
Equal expectation fails as [NULL] does not match [Integer: 1] at [.../app/tests/cases/controllers/users_controller.test.php line 80]
.../app/tests/cases/controllers/users_controller.test.php -> UsersControllerTest -> testLogin
ERROR
Unexpected PHP error [Undefined index: action] severity [E_NOTICE] in [.../cake/libs/controller/components/auth.php line 266]
.../app/tests/cases/controllers/users_controller.test.php -> UsersControllerTest -> testLogin
Here is the controller (baked plus Mark Story's "hard way" testing method):
class UsersController extends AppController
{
var $name = 'Users';
var $helpers = array('Html', 'Form');
var $components = array('Auth');
function login()
{
}
function logout()
{
$this->redirect($this->Auth->logout());
}
function index()
{
$this->set('users', $this->paginate());
}
function view($id = null)
{
if (!$id)
{
$this->Session->setFlash(__('Invalid User.', true));
$this->redirect(array('action'=>'index'));
}
$this->set('user', $this->User->read(null, $id));
}
function add()
{
if (!empty($this->data))
{
$this->User->create();
if ($this->User->save($this->data))
{
$this->Session->setFlash(__('The User has been saved', true));
$this->redirect(array('action'=>'index'));
}
else
{
$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
}
}
}
function edit($id = null)
{
if (!$id && empty($this->data))
{
$this->Session->setFlash(__('Invalid User', true));
$this->redirect(array('action'=>'index'));
}
if (!empty($this->data))
{
if ($this->User->save($this->data))
{
$this->Session->setFlash(__('The User has been saved', true));
$this->redirect(array('action'=>'index'));
}
else
{
$this->Session->setFlash(__('The User could not be saved. Please, try again.', true));
}
}
if (empty($this->data))
{
$this->data = $this->User->read(null, $id);
}
}
function delete($id = null)
{
if (!$id)
{
$this->Session->setFlash(__('Invalid id for User', true));
$this->redirect(array('action'=>'index'));
}
if ($this->User->del($id))
{
$this->Session->setFlash(__('User deleted', true));
$this->redirect(array('action'=>'index'));
}
}
}
Here is the test:
/* SVN FILE: $Id$ */
/* UsersController Test cases generated on: 2009-08-05 17:08:03 : 1249507923*/
App::import('Controller', 'Users');
class TestUsers extends UsersController
{
var $autoRender = false;
var $redirectUrl;
var $redirectStatus;
var $renderedAction;
var $renderedLayout;
var $renderedFile;
var $stopped;
function redirect($url, $status = null, $exit = true)
{
$this->redirectUrl = $url;
$this->redirectStatus = $status;
}
function render($action = null, $layout = null, $file = null)
{
$this->renderedAction = $action;
$this->renderedLayout = (is_null($layout) ? $this->layout : $layout);
$this->renderedFile = $file;
}
function _stop($status = 0)
{
$this->stopped = $status;
}
}
class UsersControllerTest extends CakeTestCase
{
var $fixtures = array('user');
var $Users = null;
function startTest()
{
$this->Users = new TestUsers();
$this->Users->constructClasses();
$this->Users->Component->initialize($this->Users);
}
function prepareForAction()
{
$this->Users->beforeFilter();
$this->Users->Component->startup($this->Users);
}
function endTest()
{
$this->Users->Session->destroy();
unset($this->Users);
ClassRegistry::flush();
}
//-----------------------------------------------------------------------
function testUsersControllerInstance()
{
$this->assertTrue(is_a($this->Users, 'UsersController'));
}
function testLogin()
{
$this->Users->data = array(
'User' => array(
'username' => 'admin',
'password' => 'admin'
)
);
$this->prepareForAction();
$this->Users->login();
$this->assertNotNull($this->Users->redirectUrl);
$this->assertEqual($this->Users->Session->read('Auth.User.id'), 1);
}
}
The test you have isn't really testing your UsersContoller, you're really testing the AuthComponent. If you want to do this you need to make sure you setup your TestUsersController the same as it would be in your app. In the case of your testLogin you need to set the controller's action and url:
function testLogin()
{
$this->Users->data = array(
'User' => array(
'username' => 'admin',
'password' => 'admin'
)
);
$this->Users->params['url']['url'] = '/users/login';
$this->Users->params['action'] = 'login';
$this->prepareForAction();
$this->Users->login();
$this->assertNotNull($this->Users->redirectUrl);
$this->assertEqual($this->Users->Session->read('Auth.User.id'), 1);
}
Alternately, I would suggest taking another look at Mark's mock objects post and using those methods to write tests for the controller code and mocking the auth component.