How to access userinfo in angularjs application after successful login - angularjs

im developing an test application in angularjs and authenticating my user from login page,
Express Code:
exports.login = function (req, res, next) {
passport.authenticate('local', function(err, user, info) {
var error = err || info;
if (error) return res.json(401, error);
req.logIn(user, function(err) {
if (err) return res.send(err);
res.json(req);
});
})(req, res, next);
};
Service : (Auth and Session)
Auth Service code:
login: function(user, callback) {
var cb = callback || angular.noop;
return Session.Sessionlogin().save({
email: user.email,
password: user.password
}, function(user) {
$rootScope.currentUser = user;
return cb();
}, function(err) {
return cb(err);
}).$promise;
},
Session Service Code:
Sessionlogin: function(){
return $resource('/api/session/');
Controller Code:
$scope.login = function(form) {
$scope.submitted = true;
if(form.$valid) {
Auth.login({
email: $scope.user.email,
password: $scope.user.password
})
.then( function(err) {
// todo : redirect to admin dashboard
$location.path('admin/dashboard');
})
.catch( function(err) {
err = err.data;
$scope.errors.other = err.message;
});
}
};
every thing work fine now my question is :
after successful login im redirecting the user to dashboard page.Now how can i access the userinfo in dashboard page.Is there any kind of session object in angularjs where i can store the response received from the express code and send it to the dashboard page.

To share data around an angular app, you can either:
Store the data in a service which can then be injected into controllers whenever you need to access that data. Services are singletons: there'll only ever be one instance of each service which is why the data is persistent across controllers.
Store data in $rootScope. It looks like you've already set the user object on the root scope, so you can access it as $rootScope.currentUser provided that you have injected $rootScope into your controller. Note that it's not usually a good idea to litter the root scope, but in this case I think it is wise to store the user object there because you will probably need to access it from a lot of views.
I usually store the user object in $rootScope (so that it's accessible from views) and in a dedicated service (so that it's accessible from controllers/etc).

Related

PassportJS with NodeJS not returning errors (MEAN stack)

I'm running a MEAN stack with PassportJS for authentication, and I'm having an issue with my signup module interacting with my Angular controller. Basically, the errorCallback is never called, and I'm not sure how to properly use the Passport done() implementation.
I have a basic signup form that upon submission, calls this request:
$http.post('/api/signup', {
name: $scope.user.name,
email: $scope.user.email,
password: $scope.user.password,
userSince: new Date().now
}).then(
function successCallback(res) {
$rootScope.message = 'Account Created';
console.log('Success'+res);
console.dir(res,{depth:5});
$location.url('/signupConf');
}, function errorCallback(res) {
$rootScope.message = 'Failure, see console';
console.log('Error: '+res);
console.dir(res,{depth:5});
$location.url('/');
});
With the express route:
app.post('/api/signup', passport.authenticate('local-signup'),function(req, res) {
console.log('User: ' + req.user.email);
});
And finally the Passport (adapted from a Scotch.io tut) module, abridged a little:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
console.log("Signup Request: "+email);
process.nextTick(function() {
User.findOne({ 'email' : email }, function(err, user) {
if (err) { return done(err); }
// check to see if theres already a user with that email
if (user) {
console.log("User not created, already exsists: "+user);
return done(err, false, {message: 'Username already exsists.'});
} else {
// if there is no user with that email
// create the user
var newUser = new User();
//a bunch of data creation here
newUser.save(function(err) {
if (err) {throw err;}
console.log("Sucessfully created: "+newUser);
return done(null, newUser);
});
}
});
});
}));
Everything runs fine, users are created corrected, and if a user with a given email exists, a new one isn't written over it. However, no matter what, successCallback is called. When a username already exist, I can see a 401 error in the browser console. When its a bad request (i.e. not all fields filled), a 400 error.
All the server side console.logs work fine, leading me to think there's something wrong in my angular frontend, or how the backend is responding to the request.
(Scotch.io tutorial credit: https://scotch.io/tutorials/easy-node-authentication-setup-and-local)
The problem was sort of staring me in the face, it was in my route handling.
app.post('/api/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err,user,response) {
//handle responses based on state of user and err
})
(req, res, next);
});

Ionic Facebook Connect

I'm pretty new to developing in Ionic and I'm trying to integrate my application with Facebook login. I found this tutorial https://ionicthemes.com/tutorials/about/native-facebook-login-with-ionic-framework and I did everything the way it was shown but I'm getting the following error
TypeError: Cannot read property 'getLoginStatus' of undefined
at Scope.$scope.facebookSignIn (controllers.js:547)
at $parseFunctionCall (ionic.bundle.js:21172)
at ionic.bundle.js:53674
at Scope.$eval (ionic.bundle.js:23228)
at Scope.$apply (ionic.bundle.js:23327)
at HTMLAnchorElement.<anonymous> (ionic.bundle.js:53673)
at HTMLAnchorElement.eventHandler (ionic.bundle.js:11841)
at triggerMouseEvent (ionic.bundle.js:2865)
at tapClick (ionic.bundle.js:2854)
at HTMLDocument.tapTouchEnd (ionic.bundle.js:2977)
My Code for the controller is as follows:
.controller('WalkthroughCtrl', function($scope, $state, $q, UserService, $ionicLoading) {
var fbLoginSuccess = function(response) {
if (!response.authResponse){
fbLoginError("Cannot find the authResponse");
return;
}
var authResponse = response.authResponse;
getFacebookProfileInfo(authResponse)
.then(function(profileInfo) {
// For the purpose of this example I will store user data on local storage
UserService.setUser({
authResponse: authResponse,
userID: profileInfo.id,
name: profileInfo.name,
email: profileInfo.email,
picture : "http://graph.facebook.com/" + authResponse.userID + "/picture?type=large"
});
$ionicLoading.hide();
$state.go('app.feeds-categories');
}, function(fail){
// Fail get profile info
console.log('profile info fail', fail);
});
};
// This is the fail callback from the login method
var fbLoginError = function(error){
console.log('fbLoginError', error);
$ionicLoading.hide();
};
// This method is to get the user profile info from the facebook api
var getFacebookProfileInfo = function (authResponse) {
var info = $q.defer();
facebookConnectPlugin.api('/me?fields=email,name&access_token=' + authResponse.accessToken, null,
function (response) {
console.log(response);
info.resolve(response);
},
function (response) {
console.log(response);
info.reject(response);
}
);
return info.promise;
};
//This method is executed when the user press the "Login with facebook" button
$scope.facebookSignIn = function() {
facebookConnectPlugin.getLoginStatus(function(success){
if(success.status === 'connected'){
// The user is logged in and has authenticated your app, and response.authResponse supplies
// the user's ID, a valid access token, a signed request, and the time the access token
// and signed request each expire
console.log('getLoginStatus', success.status);
// Check if we have our user saved
var user = UserService.getUser('facebook');
if(!user.userID){
getFacebookProfileInfo(success.authResponse)
.then(function(profileInfo) {
// For the purpose of this example I will store user data on local storage
UserService.setUser({
authResponse: success.authResponse,
userID: profileInfo.id,
name: profileInfo.name,
email: profileInfo.email,
picture : "http://graph.facebook.com/" + success.authResponse.userID + "/picture?type=large"
});
$state.go('app.feeds-categories');
}, function(fail){
// Fail get profile info
console.log('profile info fail', fail);
});
}else{
$state.go('app.home');
}
} else {
// If (success.status === 'not_authorized') the user is logged in to Facebook,
// but has not authenticated your app
// Else the person is not logged into Facebook,
// so we're not sure if they are logged into this app or not.
console.log('getLoginStatus', success.status);
$ionicLoading.show({
template: 'Logging in...'
});
// Ask the permissions you need. You can learn more about
// FB permissions here: https://developers.facebook.com/docs/facebook-login/permissions/v2.4
facebookConnectPlugin.login(['email', 'public_profile'], fbLoginSuccess, fbLoginError);
}
});
};
})
Thank You in Advance.

Angular API call fails in MEAN application

In a MEAN app I am trying to allow an authorised user (email and password login) to change their username.
I can successfully use Postman to PUT a new username to http://localhost:3000/api/users/xxxxxxxxxxxxxxxx.
But the angular code fails.
Here is the relevant part of the edit page:
<form ng-submit="user.saveUser()">
<div class="form-group">
<label> New Username</label>
<input type="text" class="form-control" ng-model="user.userData.name">
</div>
Here is the controller:
.controller('userEditController', function($routeParams, User) {
var vm = this;
vm.type = 'edit';
User.get($routeParams.user_id)
.success(function(data) {
vm.userData = data;
});
// function to save the user
vm.saveUser = function() {
vm.processing = true;
vm.message = '';
// call the userService function to update
User.update($routeParams.user_id, vm.userData)
.success(function(data) {
vm.processing = false;
// clear the form
vm.userData = {};
// bind the message from our API to vm.message
vm.message = data.message;
});
};
});
Here is the service:
// update a user
userFactory.update = function(id, userData) {
return $http.put('/api/users/' + id, userData);
};
at this point userData contains name: “Fred” or whatever was input to the form
and here is the api.js
apiRouter.route('/users/:user_id')
// get the user with that id
.get(function(req, res) {
User.findByIdAndUpdate(req.params.user_id, function(err, user) {
if (err) return res.send(err);
// return that user
res.json(user);
});
})
// update the user with this id
.put(function(req, res) {
console.error(req.params.user_id);
User.findById(req.params.user_id, function(err, user) {
if (err) return res.send(err);
// set the new user information if it exists in the request
if (req.body.name) user.name = req.body.name;
// save the user
user.save(function(err) {
if (err) return res.send(err);
// return a message
res.json({ message: 'User updated!' });
});
});
});
(I had to use findByIdAndUpdate instead of findById because of a CastError.)
Although the console states:
XHR finished loading: PUT http:/localhost/3000/api/users/user_id
The value of req.params.user_id is just user_id.
The terminal shows:
PUT /api/users/user_id 200 4.040 ms - 2273
GET /api/users/user_id - - ms - -
GET /api/users/user_id - - ms - -
GET /api/users/user_id - - ms - -
Like I say Postman can communicate with the API and can update without problems. I am stumped, and hopefully someone will put me out of my misery
I had to change tack with this one. The fact that a manually entered user_id in Postman worked should have told me that the user_id provided by the Angular code was not correct. So I made sure that the JWT included the user_id:
var token = jwt.sign({
name: user.name,
email: user.email,
user_id: user._id
Then added an api endpoint to get user information:
apiRouter.get('/me', function(req, res) {
res.send(req.decoded);
});
Then connected a service:
userFactory.get = function() {
return $http.get('/api/me/');
};
Then in the controller I could call get:
User.get()
.success(function(result) {
$scope.user_id = result.user_id;
});
$scope.user_id now has the correct user_id which I can pass into the update method:
User.update($scope.user_id, vm.userData)
.success(function(data)
So now it works as intended.

How can I return a database query and redirect at once?

I don't literally need to use "res.redirect()", I just mean I want to take the user to a different page using any workable method.
After the user enters their info, they click a button which calls createUser. createUser successfully adds a new entry to the database. I want the user to also be automatically redirected back to the index page ("/"). I have not found any way to do this. What I have below does hit "app.get('/'), but no redirect happens. Is it possible to put the redirect in app.post('/api/register-new-user')? Can I use window.location somehow within createUser? I have tried both of those ways to no avail.
// CLIENT =====
$scope.createUser = function() {
$http.post('/api/register-new-user', $scope.formData)
.success(function(data) {
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.users = data;
console.log(data);
// window.location = "./";
})
.error(function(data) {
console.log('Error: ' + data);
});
$http.get('/')
.success(function(data) {
})
.error(function(data) {
console.log('Error: ' + data);
});
};
//SERVER========
app.post('/api/register-new-user', function(req, res) {
bcrypt.genSalt(10, function(err, salt) {
if(err)
res.send(err);
bcrypt.hash(req.body.password, salt, function(err, hash){
if(err)
res.send(err);
User.create({
username : req.body.username,
password : hash
}, function(err, user) {
if(err)
res.send(err)
User.find(function(err, users) {
if(err)
res.send(err);
res.json(users);
});
});
});
});
});
app.get('/register', function(req, res) {
console.log('register');
res.sendfile('./public/views/register.html');
});
OK, so you are doing your browser/server interaction to create a user via AJAX and HTTP redirects over AJAX have no bearing on the URL/page loaded in the browser. So you can forget about server side HTTP redirects. Just send a 201 status to be nicely RESTful and call it good on the server.
On the client, if the POST succeeds you can just trigger a new route with $location.path('/');. Just make sure you declare $location so it gets injected by DI into your controller.
Also note that the active user probably needs to be set on the $rootScope if you want it to be broadly available to the rest of your controllers.
You could try
window.location.href()
Instead of window.location().
This should work with an absolute path.
Although as you are using Angular so it is possible to use the route provider to update the view with out redirecting the user.
Here is some documentation for the route provider.
https://docs.angularjs.org/tutorial/step_07

Passport.js Google authentication returns blank error

Trying to use passport.js in my Angular app to use google authentication.
The way I have my express endpoints set up is:
app.set('client-google-signin-path', '/google');
app.route('/auth/google')
.get(function(req, res, next) {
var mobileApp = req.headers.origin;
passport.authenticate('google', { scope: ['profile', 'email'], callbackURL: mobileApp + req.app.get('client-google-signin-path')})(req, res, next);
});
app.route('/auth/google/callback')
.get(function(req, res, next) {
//NEVER MAKES IT HERE
var mobileApp = req.headers.origin;
passport.authenticate('google', {scope: ['profile', 'email'], callbackURL: mobileApp + req.app.get('client-google-signin-path')},
function(err, user, info) {
var profile;
if(err) return next(err);
if(!info || !info.profile) return res.status(400).send("Profile not available.");
// Grab the profile info returned from google.
profile = info.profile._json;
//model logic
User.findOne({ 'email': profile.email }, function(err, user) {
if(err) return next(err);
if(!user) return res.status(400).send("There does not appear to be an account that matches, you may need to create an account and try again.");
req.logIn(user, function(err) {
if(err) return next(err);
return res.status(200).send(user);
});
});
res.status(200);
})(req, res, next);
});
My controller looks like:
$scope.signInGoogle = function() {
return $http.get(backendConst.location + 'auth/google')
.success(function(url) {
// Redirect to google.
$window.location.href = url;
});
};
$scope.signInGoogleCallback = function() {
return $http.get(backendConst.location + 'auth/google/callback', {
params: $location.search()
})
.success(function(user) {
$scope.gRes = 'Success!';
$location.search('code', null);
$location.hash(null);
AuthModel.setUser(user);
$location.path('/');
})
.error(function(err) {
$scope.gRes = 'Authentication failed, redirecting.';
$location.path('/authenticate');
});
And for good measure, my dinky little /google redirect page is:
<div class="container clearfix" ng-init="signInGoogleCallback()">
<h1>Google YO!</h1>
<h4>{{gRes}}</h4>
</div>
So what's happening is that it brings in the "log in with google" page, lets me select my account, then when it calls the callback it quickly flashes the /google view but then kicks me back out into /authenticate, the view I started in. Doing some debugging shows that
return $http.get(backendConst.location + 'auth/google/callback', {
params: $location.search()
})
is throwing a blank "err" even though in my endpoint logs it's saying that /auth/google/callback returned a 200. I'm not sure what's happening. I know this looks needlessly complicated but I do it this way with facebook and passport.js and everything works fine, except my endpoint logs are showing that with facebook the parameter "?code=" is being added to the /auth/facebook/callback url, like I'm trying to do with {params: $location.search()} in my google callback function in my controller. Debugging into the endpoint shows that it never makes it to where I left the //NEVER MAKES IT HERE comment, but when removing the {params: $location.search()} option it makes it passport.authenticate but not beyond. I'm completely stumped. Again I should stress that I handle facebook authentication the exact same way and it works perfectly.

Resources