CakePHP remember me with Auth - php

I have successfully used Auth, but unfortunately, it seems that it does work only with Session. I want that if user checks "Remember Me" checkbox, I would use Cookie and he would be logged in for 2 weeks. I can't find anything in official book and in Google I found just few and not great blog posts. Is there any way to implement this without rewriting the core?

In your user controller:
public function beforeFilter() {
$this->Auth->allow(array('login', 'register'));
parent::beforeFilter();
}
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
// did they select the remember me checkbox?
if ($this->request->data['User']['remember_me'] == 1) {
// remove "remember me checkbox"
unset($this->request->data['User']['remember_me']);
// hash the user's password
$this->request->data['User']['password'] = $this->Auth->password($this->request->data['User']['password']);
// write the cookie
$this->Cookie->write('remember_me_cookie', $this->request->data['User'], true, '2 weeks');
}
return $this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash(__('Username or password is incorrect.'));
}
}
$this->set(array(
'title_for_layout' => 'Login'
));
}
public function logout() {
// clear the cookie (if it exists) when logging out
$this->Cookie->delete('remember_me_cookie');
return $this->redirect($this->Auth->logout());
}
In the login view:
<h1>Login</h1>
<?php echo $this->Form->create('User'); ?>
<?php echo $this->Form->input('username'); ?>
<?php echo $this->Form->input('password'); ?>
<?php echo $this->Form->checkbox('remember_me'); ?> Remember Me
<?php echo $this->Form->end('Login'); ?>
In your AppController:
public $components = array(
'Session',
'Auth',
'Cookie'
);
public $uses = array('User');
public function beforeFilter() {
// set cookie options
$this->Cookie->key = 'qSI232qs*&sXOw!adre#34SAv!#*(XSL#$%)asGb$#11~_+!##HKis~#^';
$this->Cookie->httpOnly = true;
if (!$this->Auth->loggedIn() && $this->Cookie->read('remember_me_cookie')) {
$cookie = $this->Cookie->read('remember_me_cookie');
$user = $this->User->find('first', array(
'conditions' => array(
'User.username' => $cookie['username'],
'User.password' => $cookie['password']
)
));
if ($user && !$this->Auth->login($user['User'])) {
$this->redirect('/users/logout'); // destroy session & cookie
}
}
}

See this URL i think it is very help full to you.
http://lecterror.com/articles/view/cakephp-and-the-infamous-remember-me-cookie
Or Try this
function login() {
if ($this->Auth->user()) {
if (!empty($this->data) && $this->data['User']['remember_me']) {
$cookie = array();
$cookie['username'] = $this->data['User']['username'];
$cookie['password'] = $this->data['User']['password'];
$this->Cookie->write('Auth.User', $cookie, true, COOKIE_EXPIRE);
unset($this->data['User']['remember_me']);
}
$this->LogDetail->Write('activity','has logged IN');
$this->redirect($this->Auth->redirect());
}
if (empty($this->data)) {
$cookie = $this->Cookie->read('Auth.User');
if (!is_null($cookie)) {
if ($this->Auth->login($cookie)) {
$this->Session->destroy('Message.Auth'); # clear auth message, just in case we use it.
$this->LogDetail->Write('activity','has been authenticated via cookie and is now logged IN');
$this->redirect($this->Auth->redirect());
} else {
$this->LogDetail->Write('activity','attempted to gain access with an invalid cookie');
$this->Cookie->destroy('Auth.User'); # delete invalid cookie
$this->Session->setFlash('Invalid cookie');
$this->redirect('login');
}
}
}
}

use CookeAuthenticate adapter:
https://github.com/ceeram/Authenticate/blob/master/Controller/Component/Auth/CookieAuthenticate.php
here more info:
https://github.com/ceeram/Authenticate/wiki/Set-Cookie

Remember me is nothing else but session identified with a cookie, but cookie lifetime set to infinity. Look at Config/core.php for session cookie lifetime.

I think you need to know about CakePHP Security levels. Try to lower the security of your cakePHP. CakePHP's Config variables documentation. I had written a blog about it also a long ago.

you can try this
if ($this->Auth->login())
{
if (!empty($this->data['User']['remember']))
{
$cookie = array();
$cookie['login'] = $this->data['User']['login'];
$cookie['password'] = $this->data['User']['password'];
$cookie['language'] =$this->data['User']['language'];
$this->Cookie->write('Auth.projectname', $cookie, true, '+1 years');
unset($this->data['User']['remember']);

public function admin_login() {
$this->layout = 'admin_login';
if (count($this->Session->read("Auth.User"))) {
$usr = $this->Session->read("Auth.User");
if ($usr['role'] == 'A' || $usr['role'] == 'RA' || $usr['role'] == 'MAfA' || $usr['role'] == 'Af' || $usr['role'] == 'FAA')
return $this->redirect(array('controller' => 'dashboard', 'action' => 'view'));
}
if ($this->request->is('post')) {
if ($this->request->data['User']['remember_me']=="1") {
// pr($this->request->data);
// die('sdd');
$this->Cookie->write('username', $this->request->data['User']['username'], true, '1 year');
$this->Cookie->write('password', $this->request->data['User']['password'], true, '1 year');
} else {
$this->Cookie->destroy();
}
/*
* Check if email or username is passed in form
*/
$uname = $this->request->data['User']['username'];
//login via email
if (filter_var($uname, FILTER_VALIDATE_EMAIL)) {
$u = $this->User->findByemail($uname);
} else { //login via username
$u = $this->User->findByusername($uname);
}
if ($u) {
$this->request->data['User']['username'] = $u['User']['username'];
/* * *
* Error if user is not active
*/
if ($u['User']['user_status'] != 'active') {
$this->Session->setFlash(__('Sorry! Your account is not active.'), 'default', array('class' => 'alert alert-danger'));
} elseif ($this->Auth->login()) { //if logged in
$user_caps = $this->fetchCapabilitiesByRole($u['User']['role']);
$this->Session->write("Auth.User.privileges", array('capabilities' => $user_caps['capabilities'], 'geo_areas' => array()));
if ($u['User']['role'] == 'A' || $u['User']['role'] == 'RA' || $u['User']['role'] == 'Af' || $u['User']['role'] == 'MAfA' || $u['User']['role'] == 'FAA')
return $this->redirect(array('controller' => 'dashboard', 'action' => 'view'));
return $this->redirect($this->Auth->redirect());
}else { //if invalid
$this->Session->setFlash(__('Invalid username or password.'), 'default', array('class' => 'alert alert-danger'));
}
} else {//if user does not exists
$this->Session->setFlash(__('User does not exists.'), 'default', array('class' => 'alert alert-danger'));
}
}
}

It's been a while since the question was answered but hopefully this can help to ones that come after me.
I've written short walkthrough on how to setup 'remember me' functionality using Auhenticate Plugin from Ceeram
More info here: http://mirkoborivojevic.com/posts/2013/08/10/setup-remember-me-functionality-in-cakephp/

Related

Cannot redirect to login page if user not authenticated using constructor

I have an Admin controller which handles the user login and other admin functionality like managing a basic cms. In the constructor I check if the users session present which is set once they login. If not and they try to access a restricted page, they should be redirected. If I redirect to another page then when going to the login page I get redirected right away as obviously that check is done in the constructor, but as soon as I try to redirect to the login page I get an error:
This page isn’t working localhost redirected you too many times. Try
clearing your cookies. ERR_TOO_MANY_REDIRECTS
class Admin extends Controller {
public function __construct()
{
if(!isLoggedIn()) {
redirect('admin/login');
}
$this->AuthModel = $this->model('Auth');
}
isLoggedIn is a function:
function isLoggedIn() {
if(isset($_SESSION['user_id']) && isset($_SESSION['browser']) && $_SESSION['browser'] == $_SERVER['HTTP_USER_AGENT']) {
return true;
} else {
return false;
}
}
Login method:
public function login()
{
if($_SERVER['REQUEST_METHOD'] == 'POST') {
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$password = trim($_POST['password']);
$data = [
'email' => $email,
'password' => $password,
'email_error' => '',
'pass_error' => '',
'no_user' => '',
'pass_wrong' => ''
];
if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$data['email_error'] = 'Invalid email address <br />';
}
if(empty(trim($_POST['password']))) {
$data['pass_error'] = 'Password required';
}
if(!empty(trim($_POST['email'])) && !$this->AuthModel->getUserByEmail($email)) {
$data['no_user'] = 'Email does not exist';
}
if(!empty($data['email_error']) || !empty($data['pass_error']) || !empty($data['no_user'])) {
$this->view('admin/login', $data);
} else {
$loggedInUser = $this->AuthModel->login($email, $password);
if($loggedInUser) {
$this->CreateUserSession($loggedInUser);
} else {
$data['pass_wrong'] = 'Incorrect login details';
$this->view('admin/login', $data);
}
}
} else {
$data = [
'email' => '',
'password' => '',
'email_error' => '',
'pass_error' => '',
'no_user' =>'',
'pass_wrong' => ''
];
$this->view('admin/login', $data);
}
}
You are using same controller for login and other functionalities. Every time it checks for authentication and it gets no. And it loops over again. try to implement your login functionalities in a separate Controller.

Logout is not working in CI 3

I am trying to log out for the logged in users .
But its not working ,after log out ,i am getting session data also .
Below is my code .please have a look.
public function logout() {
if ($this->session->userdata('login') == "true") {
$current_user_data = $this->session->userdata('current_user_data');
$type = $current_user_data['type'];
$user_id = $current_user_data['user_id'];
$token = $current_user_data['token'];
$logout = $this->school->logout($type, $user_id, $token);
if (!empty($logout)) {
//echo $logout->responseCode;
if ($logout->responseCode == 200 || $logout->responseCode == 419) {
$this->session->sess_destroy();
$this->clear_cache();//clear the cache after logout //
redirect('login');
} else {
//$error['code']=json_encode(array('responseCode' => '500', 'response' => array('message' => 'error', 'statusReason' => 'internal_server_error')));
$url = "error/error_type/500";
redirect($url);
}
} else {
//echo "invalid token";
$url = "error/error_type/401";
redirect($url);
}
} else {
redirect('login');
}
}
Its going to conditions also , but session is not destroying .
Any thing wrong here?
Thank you
sess_destroy() will destroy all the sessions, even flash ones. Why don't use the simple function. I have tried this and it worked in my case. I made a session named userdata which will take user credential while he login. This is my logout function.
/**
* to logout the current session
*/
public function logout() {
$this->session->unset_userdata('user_login');
$this->load->view('index.php');
}
If you want to destroy the session data this should work fine too,
refer this further https://www.codeigniter.com/user_guide/libraries/sessions.html
Try this Method for logout
<?php
class Logout extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->helper(array('url','html'));
$this->load->library('session');
$this->load->database();
$this->load->model('users_model');
}
function index()
{
$user_data = $this->user_model->get_user_by_id($this->session->userdata('id'));
foreach ($user_data as $key => $value) {
if ($key != 'session_id' && $key != 'ip_address' && $key != 'user_agent' && $key != 'last_activity') {
$this->session->unset_userdata($key);
}
}
$this->session->sess_destroy();
redirect('Welcome', 'refresh');
}
}

Bad redirectUrl at login with CakePHP

This is what I did to reproduce my problem:
Login (redirection at page foo)
Click and go to page bar
Logout
Login again
The redirected page is bar (it should be foo)
This is what I did:
AppController.php
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'loginRedirect' => [
'controller' => 'Dashboard',
'action' => 'index'
]
]);
UsersController.php
public function login($reset = null) {
$this->layout = 'login';
$this->set('reset', $reset);
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
// IMPORTANT!
// Here I'm setting a different redirect url. The book says
// that $this->Auth->redirectUrl() will read the Auth.redirect
// session. I wanted my admin to login into a different page
if($session->read('Auth.User.role_id') === 3) {
$session->write('Auth.redirect', '/users/system_administrator_index');
}
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Flash->error('Oops', ['key' => 'auth']);
}
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
I tried to use $session->destroy(); in order to clear everything related to my session but I noticed anything.
Each time I retry to login, the server redirect me to the last page I visited the last time I was connected.
I found a workaround. Instead of using return $this->redirect($this->Auth->redirectUrl());, I do a manual redirection.
public function login($reset = null) {
$this->layout = 'login';
$this->set('reset', $reset);
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
if($user['role_id'] === 3){
return $this->redirect('/users/system_administrator_index');
}
return $this->redirect('/dashboard');
} else {
$this->Flash->error('Oops', ['key' => 'auth']);
}
}
}

How to auto redirect user having Auto-Login cookie, using Auto-Login component in CakePHP 2x?

I am using CakePHP 2x with Auto-Login component. The problem is, I can write the stuff but, I am not sure how to implement it to read and authorize. When user arrives at the page, he still has the cookie in his browser but, how do I authorize it?
My Login script:
public function login() {
if ($this->Auth->user('id')) {
$this->redirect(array('action' => 'dashboard'));
}
if($this->request->data['User']['auto_login']):
$this->AutoLogin->write($this->request->data['User']['username'],
$this->request->data['User']['password']);
endif;
if ($this->request->is('post')) {
if ($this->Auth->login( )) {
//$this->redirect(array('controller' => 'users', 'action' => 'dashboard'));
return $this->redirect($this->Auth->redirect( ));
}
else
{
$this->Session->setFlash(__('Username or Password is incorrect'), 'default', array( ), 'auth');
}
}
This should be something like:
public function login()
{
if ($this->request->is('post'))
{
if ($this->Auth->login())
{
if ($this->request->data['User']['persist'] == '1')
{
$cookie = array();
$cookie['username'] = $this->data['User']['USER_LOGINNAME'];
$cookie['password'] = $this->data['User']['USER_PASSWORD'];
$this->Cookie->write('Auth.User', $cookie, true, '+4 weeks');
}
$this->redirect($this->Auth->redirect());
}
else
{
$this->Session->setFlash('Your username or password was incorrect.', 'default/flash-error');
}
}
else
{
$user = $this->Auth->user();
if (empty($user))
{
$cookie = $this->Cookie->read('Auth.User');
if (!is_null($cookie))
{
$user = $this->User->find('first', array('conditions' => array('USER_LOGINNAME' => $cookie['username'], 'USER_PASSWORD' => AuthComponent::password($cookie['password']))));
if ($this->Auth->login($user['User']))
{
$this->Session->delete('Message.auth');
$this->redirect($this->Auth->redirect());
}
else
{
$this->Cookie->delete('Auth.User');
}
}
}
else
{
$this->redirect($this->Auth->redirect());
}
}
}
This gives you the idea of how to achieve the same task, however, I used form fields according to my DB Structure.
Kindly change the form fields according to your DB Structure.

Login with email address or username in CakePHP v2.0

In CakePHP prior to 2.0 you could allow a user to login using their email address by stopping the autoRedirect and then comparing the username data to the email column in your database (apparently Cake could then fallback to username checks if not an email).
In CakePHP 2.0 this has changed and you login manually using $this->Auth->login()
My question is how do I get this working for 2.0? I have some quite complicated code that does a variety of things such as handle ajax and postback requests, locking of accounts if a user tries to login too many times etc so it's quite long!
As you will see I check if the account actually exists manually so I can show a message of account not found before going through the authentication process if the case, and also use this to lock the account of that user if 5 fail attempts.
The main problem here is allowing the system to check on both usernames and email addresses for authentication, the system in place does LOCK the user if you use the email address as it handles that in the mentioned check, but it will always fail because the authentication cannot handle it.
Hope someone can help, offer ideas tips. Thanks
if ($this->request->is('post'))
{
$opts = array(
'conditions'=>array(
'OR'=>array(
'User.username'=>$this->data['User']['username'],
'User.email'=>$this->data['User']['username']
)
)
);
$user = $this->User->find('first', $opts);
if(!empty($user))
{
if($user['User']['status'] == 0)
{
if($this->request->is('ajax'))
{
$this->autoRender = false;
echo json_encode(array('authenticated'=>false,'error'=>__('Sorry your account is currently locked. Please reset your password.?')));
}
else
{
$this->Session->setFlash(__('Sorry your account is currently locked. Please reset your password.'), 'default', array(), 'auth');
}
}
else
{
if ($this->Auth->login())
{
if ($this->request->is('ajax'))
{
$this->autoRender = false;
if(isset($this->params['url']['continue']))
{
$pathtoredirect = $this->UrlEncode->base64url_decode($this->params['url']['continue']);
echo json_encode(array('authenticated'=>true,'redirect'=>$pathtoredirect,'base'=>false));
}
else
{
$pathtoredirect = $this->Auth->redirect();
echo json_encode(array('authenticated'=>true,'redirect'=>$pathtoredirect,'base'=>true));
}
}
else
{
if(isset($this->params['url']['continue']))
{
$pathtoredirect = $this->UrlEncode->base64url_decode($this->params['url']['continue']);
}
else
{
$pathtoredirect = $this->Auth->redirect();
}
return $this->redirect($pathtoredirect);
}
}
else
{
if($this->Session->read('attempts'))
{
$attempts = $this->Session->read('attempts') + 1;
}
else
{
$attempts = 1;
}
$this->Session->write('attempts', $attempts);
if($attempts >= 5)
{
$this->User->id = $user['User']['id'];
$this->User->saveField('status', 0);
if ($this->request->is('ajax'))
{
$this->autoRender = false;
echo json_encode(array('authenticated'=>false,'error'=>__('Username or password is incorrect. For security reasons this account has now been locked and you must reset your password to unlock it.')));
}
else
{
$this->Session->setFlash(__('Username or password is incorrect. For security reasons this account has now been locked and you must reset your password to unlock it.'), 'default', array(), 'auth');
}
}
else
{
if ($this->request->is('ajax'))
{
$this->autoRender = false;
echo json_encode(array('authenticated'=>false,'error'=>__('Username or password is incorrect')));
}
else
{
$this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
}
}
}
}
}
else
{
if ($this->request->is('ajax'))
{
$this->autoRender = false;
echo json_encode(array('authenticated'=>false,'error'=>__('Sorry that account does not exist.')));
}
else
{
$this->Session->setFlash(__('Sorry that account does not exist.'), 'default', array(), 'auth');
}
}
}
I'm not sure if the AuthComponent can be configured to check for two fields automatically, but here is an alternative:
/*
* AppController
*/
beforeFilter()
{
$this->Auth->authenticate = array('Form' => array('fields' => array('username' => 'email', 'password' => 'password')));
}
/*
* UsersController
*/
function login()
{
if($this->request->is('post'))
{
$logged_in = false;
if($this->Auth->login())
{
$logged_in = true;
}
else
{
$this->Auth->authenticate = array('Form' => array('fields' => array('username' => 'username', 'password' => 'password')));
$this->Auth->constructAuthenticate();
$this->request->data['User']['username'] = $this->request->data['User']['email'];
if($this->Auth->login())
{
$logged_in = true;
}
}
if($logged_in)
{
/*
* Do what you want here
*/
}
else
{
/*
* Do what you want here
*/
}
}
}
Then of course if you want to be able to perform only one test to check for both fields, you could move this code into a Component instead of calling the $this->Auth->login() method directly.

Categories