Does someone here know how to change the username before the Auth component reads the database?
The problem im having is im using mobile numbers as a login but i want to add the country code (if not present) when loggin in to my site
Any one have an idea on this?
Would be appreciated
If you are using CakePHP 2.0, you can manipulate the login form data as usual and then call $this->Auth->login(). Example:
// in your controller
public function login() {
if ($this->request->is('post')) {
$this->data['User']['username'] = $this->addCountryCode($this->data['User']['username']);
if ($this->Auth->login()) {
// login successful
} else {
// login not successful
}
}
}
you could always extend the Auth component and do whathever you want before the asking the database :)
Something like this...
function login($data = null,$public = false) {
$this->__setDefaults();
$this->_loggedIn = false;
if (empty($data)) {
$data = $this->data;
}
if (/** query the database to check/modify the data. You could use the identify() method of the AuthComponent **/) {
$this->Session->write($this->sessionKey, $user);
$this->_loggedIn = true;
}
return $this->_loggedIn;
}
If you extend the auth component, remember to always use this component instead of the default Auth class. (e.g. in the AppController, the build_acl, the initdb, the beforefilter on the controllers, etc.)
Hope this helps
Related
i'm developing my website with angularjs and laravel5. i wrote code for login and registration page in both angularjs and laravel5 where validate my value and insert everything works good but redirect url in laravel 5 not occur .
i wrote code like return redirect('Home/profile') in login controller. it returns total page to angularjs controller not redirecting page.
routes.php in laravel:
Route::group(array('prefix'=>'api'),function(){
Route::resource('register','Registration\RegisterController#basicForm');
Route::resource('login','Registration\RegisterController#makeLogin');
});
my controller :
public function makeLogin()
{
$email=Input::get('email');
$pwd=Input::get('pwd');
$verify=Authenticated::attempt($email,$pwd);
if($verify)
{
return redirect('Home/profile');
}
else if($verify=='user')
{
return redirect('/')->with('Email address mismatch');
}
else if($verify=='pwd')
{
return redirect('/')->with('Password Authentication Failed');
}
}
i send post request from angular js controller via factory method:
this.scope.authUserInfo.authenticateUser(this.scope.signin).then(function(data){
console.log(data.data);
});
In this console.log,display 'Home/profile' page
I can see many mistakes in the Laravel code.
What is Authenticated in your code? The authentication service in Laravel is called Auth. The way you use the attempt() method is not correct; this is the method signature:
attempt(array $credentials = array(), bool $remember = false, bool $login = true)
so you should pass the email and the password in the first parameter as an array, something like:
$verify = Auth::attempt(['email' => $email, 'password' =>
Moreover, the attempt() method returns a boolean: true on success and false on failure. Your code
if ($verify) {
// ...
} else if ($verify == 'user') {
// ...
} else if ($verify == 'pwd') {
// ...
}
has no sense and you never run the else parts because on failure false is always different from either 'user' or 'pwd'. So, when the authentication fails you reach the end of the makeLogin() method and Laravel returns a blank page.
You should use something like:
if ($verify) {
// authenticated: go to the profile page
} else {
// username OR password are wrong
}
(In my opinion you shouldn't give hints on what of the two is wrong for security reasons: a potential attacker would know if he/she guessed a right email and concentrate the attempts on guessing the password.)
If you really want to give a hint to the user on what was wrong with her data, you should use a different technique, like searching the users table for a record with the right email to know whether the user exists (the provided password was wrong) or not (the provided email was wrong).
On the client side, I don't think Angular will redirect on your own. See answer to Handle an express redirect from Angular POST, even if in that question the server uses ExpressJs and not Laravel, but the basics are the same.
You should understand that in most cases an Angular client expect to receive only data and not a full HTML page. Here is my little attempt to do what you want:
On the Laravel side:
public function makeLogin(Request $request)
{
$email = $request->get('email');
$pwd = $request->get('pwd');
if (Auth::attempt(['email' => $email, 'password' => $pwd])) {
// authenticated!
// if you return an array from a controller public method, Laravel
// will convert it to JSON; I also use the url() Laravel helper to
// generate a fully qualified url to the path
return [
'status' => 'redirect',
'to' => url('home/profile')
];
}
// failed
return [
'status' => 'failed',
'message' => 'Email or password are wrong'
];
}
Now the method will return a JSON answer. On the Angular side, you can do something like (I'm not an Angular guru, there could be mistakes here):
this.scope.authUserInfo.authenticateUser(this.scope.signin).then(function(data) {
if (data.response == 'redirect') {
$location.url(data.to);
} else {
// failed: you can show the error message
console.log(data.message);
}
});
UPDATE
I noticed there is something wrong in the routes too. Your controller does not seems a resourceful controller, so don't use the Route::resource() method. Use the get() and post() methods instead:
Route::group(array('prefix'=>'api'),function(){
Route::get('register', 'Registration\RegisterController#basicForm');
Route::post('login', 'Registration\RegisterController#makeLogin');
});
so that you can give the method that should be called in your controller.
I am using CodeIgniter controller functions.
(example)
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Me extends CI_Controller {
public function __construct()
{
parent::__construct();
if (is_logged_in()){if (is_admin()) { redirect('login'); }}
else { redirect('login');}
}
public function change_password()
{
$id=$this->session->userdata['user_data']['id'];
$data = json_decode(file_get_contents("php://input"));
$my_data=array(
'pass'=>$data->pass,
'new_pass'=>$data->new_pass,
);
$result=$this->vanesh_model->change_pass($id,$my_data);
if($result==1)
{
$arr = array('msg' => "Password changed successfuly.", 'error' => '');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==2)
{
$arr = array('msg' => "", 'error' => 'Old Password is Invalid');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==3)
{
$arr = array('msg' => "", 'error' => 'Sorry, Password change failed');
$jsn = json_encode($arr);
print_r($jsn);
}
}
}
?>
I am afraid of using angular session services, so I want to maintain sessions with only CI. What I am doing in my application is add, update, delete only if he is logged in. And I am using information stored in session. Consider the situation, suppose, I am logged in and doing something, side by side: I destroy the session using browser tools. Now I am continuing with application (doing operations like: change password). I have/had maintained error messages, success messages, its ok. If session OFF, it gives error message. But instead of error messages, I want to redirect to LOGIN page(with page refresh).
Note: For CI Login controller, I didn't used angular js. I have used angularjs only after login.
If by opening new tab I destroy the session, and come back to application's tab: I am able to perform tasks(may be with errors,). If session is OFF I see this in Browser's console: http://localhost/ums/login
This is because of CI constructor(please look over the code).
You should separate angular and CI as much as possible, since both have view-controller it creates a mess. Instead you should have CI in a separate folder, call it api, for example, after that anything you will need from CI should be acessed from angular with ajax calls.
I made a small webapp a while ago and this seemed to be the best way to organize code.
Few updates have been made to angular since then so if there's a better way please let me know
Solved.
Used javascript function. Checking session by http request everytime. If response comes "1". Means redirect to login as:
/* function for checking logged-in and role */
function check_session()
{
$.get("servercontroller/check_session", function(data, status){
if(data=="1") /* error 1 => un-athorized user */
{
window.location.href="/login-page-url";
}
});
}
In my controller
public function profile() {
$UserInfo = $this->Auth->user()
if(!empty($this->data)) {
print_r($this->data);
$this->User->save($this->data);
}
if(!empty($UserInfo['id'])){
$this->data = $this->User->find('first',array('conditions'=>array('id'=>$UserInfo['id'])));
}
}
when i submit the data it is not submitted to db and i get only previous value.
Why are you querying the session here? of course this will always get you the old data again after the save.
Use the database as always, update the database again and only then overwrite the session maybe (You seem to be using cake 1.3):
public function profile() {
$uid = $this->Session->read('Auth.User.id');
if (!empty($this->data)) {
$this->data['User']['id'] = $uid;
if ($this->User->save($this->data, true, array('email', 'first_name', 'last_name', 'id', ...))) {
// if you rely on auth session data from the user, make sure to update that here
$this->Session->write('Auth.User.email', $this->data['User']['email']); // etc
...
// OK, redirect
} else {
// ERROR
}
} else {
$this->data = $this->User->find('first', ...);
}
}
As you can see I update the session keys that have been changed.
If you are using 2.x (which you did not specify as for now) you could also use
$this->Auth->login($this->request->data['User']); // must be the User array directly
although you will have to careful to pass all the data that has been in the session before.
If you plan on using login(), it would be better to find(first) the updated record again and pass this into login() then.
But personally, I prefer to only update the fields that actually changed.
see Editing own account/profile
I'm looking for a way with the CakePHP-Facebook-Plugin log users out of my app, but not log them out of their own facebook.
If I call my apps logout() function no matter what I do I just keep getting logged back in via facebook. If I use the plugins facebook helper in the view to generate a logout button ($this->Facebook->logout()), it definetly logs the user out of my app...but it also logs them out of their own facebook which is kinda ridiculous.
So how do I work around this to log users out of my app, and but leave them logged into facebook.
To have them "logout" of your app (meaning the next time they try to use the app, they're going to be asked to authenticate your app again), then send an HTTP DELETE command to me/permissions using their user access token.
I know this is an old question, but I figured this one out just now, trying to figure this same thing out. Basically, although in the demos with webtechnick's examples, he puts "Facebook.Connect" in the AppController, but, if you want the selective logout piece, the Best place to put it is within the actual controllers that you want to use it in or put it in AppController and pass noAuth=> true into it. Either way, whichever way you choose, you set up one controller (facebook_controller.php?) to handle the logins, and set its component with the noauth set to false (which is default). That way, you have total control over whether or not the user is logged back into the site, and you can ACTUALLY log them out (with the regular redirect($this->Auth->logout());
Let me give you an idea:
app_controller.php
class AppController extends Controller {
var $components = array('Auth', 'Acl', 'Session');
//or if you want access to "$this->Connect" universally:
// array('Auth', 'Facebook.Connect' =>
// array('noauth'=>'true', 'Acl', 'Session');
}
users_controller.php:
class UsersController extends AppController{
var $helpers = array('Facebook.Facebook');
//an example of the users controller, enabling connect, but
// not authorizing the user (because logout() used by Auth is here)
var $components = array('Email', 'Session', 'Facebook.Connect' => array('createUser'=>false, 'noauth'=>true));
//login() doesnt need to be shown and can be left alone
function logout(){
if ($this->Connect->FB->getUser() == 0){
$this->redirect($this->Auth->logout());
}else{
//ditch FB data for safety
$this->Connect->FB->destroysession();
//hope its all gone with this
session_destroy();
//logout and redirect to the screen that you usually do.
$this->redirect($this->Auth->logout());
}
}
}
your "facebook_controller.php":
class FacebookaController extends AppController {
...
// i dont personally like to have his piece create my user so:
var $components = array('Facebook.Connect' => array('createUser'=>false));
...
function login(){
//just need this stub function for later
$this->autoRender = false;
}
//you also need this for deauths or they will still be able to get into the site after deauth (against policy or whatever)
function deauthorize(){
//get user id from facebook API
$uid = $this->Connect->FB->getUser();
$record = $this->User->findByFacebookId($uid);
$this->User->delete($record['id'], FALSE);
}
}
now your users/login.ctp file:
<script>
window.fbAsyncInit = function() {
FB.init({
appId : 'your app id', // App ID
channelUrl : '//'+window.location.hostname+'/facebook/channel', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code here
FB.Event.subscribe('auth.statusChange', function(response){
if (response.status == "connected"){
alert('redirecting you to auto facebook login');
//here is out default place for login
window.location.href = "http://"+window.location.hostname + "/facebook/login";
}
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
<?php e($this->Facebook->login(array('registration-url'=>'http://www.yoursite.com/facebook/signup'))); ?>
And that should be pretty much it. I hope this helps someone reading this who still needs the help.
You may want to take a look at $this->Facebook->disconnect();
It does exactly what you want.
http://projects.webtechnick.com/docs/facebook/default/FacebookHelper.html#disconnect
Have you tried killing the PHP session?
// this would destroy the session variables
session_destroy();
I would like to know how to deal with only ONE authentification process and "users" in multiple tables. I have 4 Users table: users, admins, artists, teamadmins which all have specific fields, but I would like all of these users to be able to connect via only one form on the homepage, and being redirected after that to their specific dashboards.
I think the redirections shouldn't be a problem, and some routes added should work, but I really don't know where to look/start to ake this all possible.
Cheers,
Nicolas.
EDIT: here's the final solution (thanks to deizel)
App::import('Component', 'Auth');
class SiteAuthComponent extends AuthComponent {
function identify($user = null, $conditions = null) {
$models = array('User', 'Admin', 'Artist');
foreach ($models as $model) {
$this->userModel = $model; // switch model
$this->params["data"][$model] = $this->params["data"]["User"]; // switch model in params/data too
$result = parent::identify($this->params["data"][$model], $conditions); // let cake do its thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}
CakePHP's AuthComponent only supports authentication against a single "User" model at a time. The model is chosen by setting the Auth::userModel property, but it only accepts a string and not an array of models.
You can switch the userModel on the fly with the following code, but this requires you to know in advance which model to switch to (eg. your users have to choose their account type from a dropdown):
public function beforeFilter() {
if (isset($this->data['User']['model'])) {
$this->Auth->userModel = $this->data['User']['model'];
}
}
You can likely extend the core AuthComponent to add the functionality you want by overwriting the AuthComponent::identify() method so it loops over and attempts authentication with each model:
App::import('Component', 'AuthComponent');
class AppAuthComponent extends AuthComponent {
function identify($user = null, $conditions = null) {
$models = array('User', 'Admin', 'Artist', 'TeamAdmin');
foreach ($models as $model) {
$this->userModel = $model; // switch model
$result = parent::identify($user, $conditions); // let cake do it's thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}
You will have to replace occurrences of Auth in your application with AppAuth to use your extended AuthComponent, unless you use this trick.
While annoying, I think the best solution is probably using Cake's built in ACL support (see http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html).
If you do authentication the way you're talking about, you have to keep track of permissions in your controller code, checking to see what the userModel is. If you use an access control list, the permission tree will already exist in the database, which should simplify your code a great deal, and make it more modular.
It also means restructuring your data model to have a single users table and groups table instead of entity classes for each type of user.
I just went through the process of doing this myself... :(
this is also a possibility
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->authenticate = array(
AuthComponent::ALL => array('userModel' => 'AnotherModel'),
'Form',
'Basic'
);
}
Here is the final solution as suggested by deizel and modified by Nicolas:
App::import('Component', 'Auth');
class SiteAuthComponent extends AuthComponent {
function identify($user = null, $conditions = null) {
$models = array('User', 'Admin', 'Artist');
foreach ($models as $model) {
$this->userModel = $model; // switch model
$this->params["data"][$model] = $this->params["data"]["User"]; // switch model in params/data too
$result = parent::identify($this->params["data"][$model], $conditions); // let cake do its thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}