I am using the registration form for different users? After a new user logs in, the registered users should redirect to an after-login page. We are using Auth component for the authentication.
How do I do this?
If you want the user to auto-login after registering, you can use the AuthComponent's login() method.
if ($this->User->save($this->data)) {
$this->Auth->login($this->data);
}
On newer Cakes, you only need to add
$this->Auth->login();
after you add the user into the database.
I'm not sure what the question is, but it sounds like you're wondering how to send a user somewhere after a successful login. If that's correct, try this:
$this->Auth->loginAction = array (
'controller' => 'whichever_controller',
'action' => 'desired_action',
'admin' => true
);
The admin key may not be necessary if you're not accessing /admin/whichever_controller/desired_action.
You will have to call the login method manually from your register action.
Save the username + unhashed password in an array then call it from the method after the save like this:
$data = array('username' => 'user', 'password' => $unhashedPw);
$this->User->login($data);
Related
I'm working on some admin functions to my site where a user with admin privileges is able to open a form for a given user ID. From this form they can change user permissions, alter the user password or other means.
However, when the form is constructed from the model, the password field pulls the hashed password from the database and populates the password field. As a result, when the admin goes to save the form the hashed password is treated as a plaintext and therefore hashed again, overwriting the original password.
What I need is some way to allow admin users to change the form but only have passwords hashed and updated on the database in the event that it is changed.
My thoughts are to construct the form setting password to blank:
view/User/edit.ctp:
echo $this->Form->input('User.password',array(
'value' => '',
'type' => 'password',
'autocomplete' => 'off'
)
);
And have some sort of check on the save to skip the password; but this is where I'm stuck.
controller/userscontroller.php
public function edit($id = null)
{
$this->User->id = $id;
if ($this->request->is('get'))
{
$this->request->data = $this->User->read();
} else {
//Something here????
if ($this->User->save($this->data))
{
$this->Session->setFlash('Your user has been updated.');
$this->redirect(array('action' => 'index'));
} else
{
$this->Session->setFlash('Unable to update your user.');
}
}
$this->set('groups',$this->User->Group->find('list'));//, array( 'fields' => array('id', 'name'))));
$this->set('sites',$this->User->Site->find('list'));//, array( 'fields' => array('id', 'name'))));
}
How do I check this and prevent the password from updating when there is no change?
Decided Solution:
As per the answers provided I used a second form on the same page that re-uses the signup validation that users go through. When updating site/group privileges the users are sent through one form while passwords through another.
I would build two admin forms, one for changing permissions and the other for updating the password only. While you are at it, the change password form should have a second field for validating the change.
There are some CakePHP plugins to help with managing users and specifically passwords.
I always create a new form specially for changing passwords. You should replace the password field with a link to change the password.
Alternatively, you could disable the input field and require a button to click and use javascript to remove the disabled attribute on the input element
echo $this->Form->input('User.password',array(
'value' => '',
'type' => 'password',
'autocomplete' => 'off',
'disabled' => true
)
);
Jquery because it's easy
$(function(){
$('UsersPassword').click(function(){
$(this).attr('disabled', '0');
});
});
my UserController.php has logout function that looks like this
function logout()
{
$this->Session->destroy('User');
$this->Session->setFlash('You\'ve successfully logged out.');
var_export($this->Session->read('User'));
//$this->redirect('login');
}
my view Users/index.ctp
<?php echo $this->Html->link('Logout', array('controller' => 'users', 'action' => 'logout')); ?>
When I click "log out" the var_export still displays all the User data and if I go back to Users/index.ctp it still shows me that page even though in my my UserController.php I am checking if User is set
function beforeFilter()
{
$this->__validateLoginStatus();
}
function __validateLoginStatus()
{
if($this->action != 'login' && $this->action != 'logout')
{
if($this->Session->check('User') == false)
{
$this->redirect('login');
}
}
It does not redirect to login page and just brings me to index page.
}
$this->Session->destroy();
The destroy method will delete the session cookie and all session data stored in the temporary file system.
User to remove, use better delete.
$this->Session->delete('User');
If you use the AuthComponent to authenticate the users, you can log them out by using the logout() method.
$this->Auth->logout();
See http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#logging-users-out for Cake 2 or http://book.cakephp.org/1.3/en/view/1262/logout for Cake 1.3
And if you don't use the AuthComponent at all, you should maybe have a look at it as it contains out of the box many functionalities that you have already or will likely implement yourself.
How would I create a login link on a CakePHP page that contains a query string with the current page so for example: domain.com/login/?back=/posts/This_is_a_post
and then how would I use this in the login method to send the user BACK to this url?
I have tried this: <?php echo $this->Html->link('Log in', array('controller'=>'users','action'=>'login','admin'=>false, '?'=> array('back'=>$this->here)), array('escape'=>false)); ?>
but it does this on the url /login?back=%2Fportfolio%2Fgt%2FCreatHive
how do I get it to NOT change the / in the URL
Cheers
The best way to do this is to store the last page visited in a session at some point, probably when the page is loaded in the login action or something. Why you ask? As an attacked could make a link to your site eg: yoursite.com/login?back=mysite.com/login, so that when the user logs in, you send them to my site which is an exact duplicate of your login form and get them to login again. Voila, an attacker could now easily phish your users info.
With sessions there'd be no url encoding problems either. Just something like this in your login action:
$this->Session->set('back_to', $this->referer());
// Then if they have logged in:
$backTo = $this->Session->read('back_to');
if($backTo) {
$this->redirect($back_to);
} else {
$this->redirect($this->Auth->redirect());
}
Update - Try using named parameters instead:
For your link:
echo $this->Html->link('My Link', array('controller' => 'users', 'action' => 'login', 'url' => $url));
In your users login:
function login(){
if($this->Session->read('Auth.User')){
$url = $this->params['named']['url']
// encode/decode url
$this->redirect("$url");
}
}
You can always use urlencode() and urldecode() for the $url variable.
You also need to make sure your form also sends the URL back to the login function:
echo $this->Form->create('User', array('controller' => 'users', 'action' => 'login', 'url' => $url));
for my client's website I have an admin section- only thing is my admin routing doesn't seem to be password protected. I added the admin protection with a tutorial on how to set up a user system, and have placed the following code in app_controller.php:
function beforeFilter() {
// if an admin route is requested and not logged in
$user = $this->Session->read('User');
if(isset($this->params['admin']) && $this->params['admin'] && is_null($user)) {
// set Flash and redirect to login page
$this->Session->setFlash('You need to be logged in for that action.','default',array('class'=>'flash_bad'));
$this->redirect(array('controller'=>'users','action'=>'login','admin'=>FALSE));
}
}
& in my app/config/routes.php I have this:
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/admin/logout', array('controller' => 'users', 'action' => 'logout'));
which I'm pretty sure is missing something for the protection.
I can still access other admin areas without logging in though, i.e. theowlhouse.com.au/admin/bookings.
What am I doing wrong? The admin page for the users model is the only protected one.
Thanks :)
It looks like you're confusing prefix routing with using the auth component. Note that prefix routing was called 'admin routing' prior to version 1.3.
You don't need to use admin routing to use the auth component. Let's start with just getting the auth component set up. In your app controller, make sure you have it included in your components array:
var $components = array('Auth');
Once you've done that, users will be directed to a login page unless they are logged in. To allow anonymous users to access an action, you make a called to $this->Auth->allow('action name'); So, for example, say you want to allow unauthenticated users to use the index() and view() actions in your items controller, but not add() or edit(). In your items_controller.php, you would set up the beforeFilter() to make a call:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow(array(
'index',
'view'
));
}
I am trying to implement facebook Connect to my cakephp Application. i am using Nick's Facebook Plugin.
I wanna implement it this way
When a user Visits the Site he should be able to login via Registration on the site or Facebook Connect
Existing users should be able to connect their account to their FB account
People who first time login to the site using FB Connect and dont have an account on the site. should be redirected to a page where they have to enter details to complete the profile.
What i have done -
I have followed the instruction of Nick to implement it and when i click Login - it connects to my app. but i dont understand how to create a username and password associated with the Fb Connect Id. and user it against the FB token.
Apparently I'm doing the same thing a little before you... ;-)
Here's a method for Facebook login I'm using (slightly redacted and annotated):
public function facebook($authorize = null) {
App::import('Lib', 'Facebook.FB');
$Fb = new FB();
$session = $Fb->getSession();
// not logged into Facebook and not a callback either,
// sending user over to Facebook to log in
if (!$session && !$authorize) {
$params = array(
'req_perms' => /* the permissions you require */,
'next' => Router::url(array('action' => 'facebook', 'authorize'), true),
'cancel_url' => Router::url(array('action' => 'login'), true)
);
$this->redirect($Fb->getLoginUrl($params));
}
// user is coming back from Facebook login,
// assume we have a valid Facebook session
$userInfo = $Fb->api('/me');
if (!$userInfo) {
// nope, login failed or something went wrong, aborting
$this->Session->setFlash('Facebook login failed');
$this->redirect(array('action' => 'login'));
}
$user = array(
'User' => array(
'firstname' => $userInfo['first_name'],
'lastname' => $userInfo['last_name'],
'username' => trim(parse_url($userInfo['link'], PHP_URL_PATH), '/'),
'email' => $userInfo['email'],
'email_validated' => $userInfo['verified']
),
'Oauth' => array(
'provider' => 'facebook',
'provider_uid' => $userInfo['id']
)
);
$this->oauthLogin($user);
}
This gives me an array with all the user details I could grab from Facebook and invokes ::oauthLogin, which either logs the user in with the given information or asks the user to fill in missing details and/or creates a new user record in the database. The most important part you get from the Facebook API is the $userInfo['id'] and/or email address, either of which you can use to identify the user in your database. If you're using the AuthComponent, you can "manually" log in the user using $this->Auth->login($user_id), where $user_id is the id of the user in your own database.
private function oauthLogin($data) {
$this->User->create();
// do we already know about these credentials?
$oauth = $this->User->Oauth->find('first', array('conditions' => $data['Oauth']));
if ($oauth) {
// yes we do, let's try to log this user in
if (empty($oauth['User']['id']) || !$this->Auth->login($oauth['User']['id'])) {
$this->Session->setFlash('Login failed');
}
$this->redirect('/');
}
// no we don't, let's see if we know this email address already
if (!empty($data['User']['email'])) {
$user = $this->User->find('first', array('conditions' => array('email' => $data['User']['email'])));
if ($user) {
// yes we do! let's store all data in the session
// and ask the user to associate his accounts
$data['User'] = array_merge($data['User'], $user['User']);
$data['Oauth']['user_id'] = $user['User']['id'];
$this->Session->write('Oauth.associate_accounts', $data);
$this->redirect(array('action' => 'oauth_associate_accounts'));
}
}
// no, this is a new user, let's ask him to register
$this->Session->write('Oauth.register', $data);
$this->redirect(array('action' => 'oauth_register'));
}
Look no further. Here is an excellent article that'll guide you all the way through (minus any readymade plugins):
Integrating Facebook Connect with CakePHP's Auth component
Simply follow the approach described in there.
Cheers,
m^e