I am creating token at login time with node.js:
apiRoutes.put('/login', function(req, res, next){
User.findOne({email:req.body.email}, function(err, user){
bcrypt.compare(req.body.password, user.password, function(err, result){
if(result){
var token=jwt.encode(user,config.secret);
return res.json({success: true, token:'JWT' +token});
}else{
return res.json("Incorrect Email and Password")
}
})
})
});
now I am trying to show user dashboard page with /dashboard route and I am doing something like below:
apiRoutes.get('/dashboard',function(req, res) {
var token=getToken(req.headers);
if(token){
var decode=jwt.decode(token, config.secret);
console.log(decode);
User.findOne({name:decode.name}, function(err, user){
if(err){res.json(err)}
if(!user){
return res.status(403).send({success:false, msg:'Authentication Failed'})
}else{
res.json({success:true, msg:'Welcome in the Area ' +user.name+'!' })
}
})
}else{
return res.status(403).send({success:false, msg:'No Token Found'})
}
});
getToken = function (head) {
if (head && head.authorization) {
var parted = head.authorization.split(' ');
if (parted.length == 2) {
return parted[1];
} else {
return null;
}
} else {
return null;
}
};
In postman when I hit /dashboard api its working good. and printing the output success:true, msg:'Welcome in the Area Admin;
But when in angular js I am consuming this api then output in node console is null.
Below is my angular function to consume api
app.controller('dashboardCtrl', function($scope, $http, $location, $routeParams){
$http.get('/api/dashboard').success(function(res){
$scope.result=res;
})
})
I want to know how to consume token based route in angular. I know above given angular function is not right. Please let me know the right code.
Thanks
You didn't set the header for the $http.get(). Here is how you should do:
$http.get('/api/dashboard', {
headers: {
// Set header for the request here
authorization: token
}
})
.success(function(res) {
// Success
});
Related
I create a jwt token and stored in database. when login successfully done i want to redirect to home page with token. how could i do that.
My Nodejs file.
app.post('/authenticate', function(req, res, next) {
User.findOne({name: req.body.name}, function(err, user) {
if (err) {throw err;}
if (!user) {
res.json({ success: false, message: 'Authentication failed. User not found.' });
} else if (user) {
// check if password matches
if (user.password !== req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' });
} else {
// if user is found and password is right
// create a token
var token = jwt.sign(user, app.get('superSecret'), {
expiresIn: 1440 // expires in 24 hours
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});
My angularjs file
var app = angular.module('loginApp', []);
// Controller function and passing $http service and $scope var.
app.controller('loginCtrl', function($scope, $http) {
// create a blank object to handle form data.
$scope.user = {};
// calling our submit function.
$scope.submitForm = function() {
// Posting data to file
$http.post('/tokken/login/', $scope.user).then(function (response) {
//$http.defaults.headers.common['Token'] = token
if (response.errors) {
// Showing errors.
$scope.errorName = response.errors.name;
$scope.erroPassword = response.errors.password;
} else {
$scope.message = response.data;
}
});
};
});
I print token value in same login page. I want to redirect to another page with the token
I'm very new to angular, so my knowledge is based on tutorials and even then I don't succeed.
I need to authenticate using a google account. That works, I get a token where my api calls could be authorized with. But after login the pop up window should dismiss and I should be redirected to the homepage. This doesn't work.
this is my controller
angular.module('MyApp').controller('loginController', ['$scope', '$auth', '$location','loginService', loginController]);
function loginController($scope, $auth, $location, loginService) {
$scope.authenticate = function(provider) {
$auth.authenticate(provider).then(function(data) {
loginService.saveToken(data.data.token);
console.log('You have successfully signed in with ' + provider + '!');
$location.path('http://localhost/#/home');
});
};
};
in app.js I have my configuration. this is not my work but a friend who is an intern as wel as me, he is responsible for a mobile application, where he uses the same function to get his token, and it works.
authProvider.google({
clientId: CLIENT_ID,
redirectUri: 'http://localhost:3000/api/users/signIn'
});
$authProvider.storage = 'localStorage'; // or 'sessionStorage'
$authProvider.loginRedirect = 'http://localhost/#/home';
This is the controller in node where the url is redirected to (google developer console)
router.get('/signIn', function(req, res) {
//console.log(req);
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
if (!err) {
https.get("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + tokens.access_token, function(response) {
// Continuously update stream with data
var body = '';
response.setEncoding('utf8');
response.on('data', function(d) {
body += d;
});
// Data fetched
response.on('end', function() {
var parsed = JSON.parse(body);
// Check if client_id is from the right app
if (parsed.issued_to == '343234242055-vd082vo0o8r8lmfvp1a973736fd98dht.apps.googleusercontent.com') {
User.getGoogleId(parsed.user_id, function(err, user) {
if (err) {
res.status(500).send({
message: 'not authorized app'
});
}
// No user returned, create one
if (!user) {
// Request user info
oauth2Client.setCredentials(tokens);
plus.people.get({
userId: 'me',
auth: oauth2Client
}, function(err, plusUser) {
if (err) res.status(500).send({
message: 'not authorized app'
});
else {
// Create new user
User.create(plusUser.name.givenName, plusUser.name.familyName, (plusUser.name.givenName + "." + plusUser.name.familyName + "#cozmos.be").toLowerCase(), parsed.user_id, function(err, newUser) {
if (err) res.status(500).send({
message: 'not authorized app'
});
else {
res.statusCode = 200;
return res.send({
response: 'Success',
id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
token: tokens.access_token
});
}
});
}
});
} else {
// Return user
res.statusCode = 200;
return res.send({
response: 'Success',
id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
token: tokens.access_token
});
}
});
}
// if not right app, return unauthorized response
else {
res.status(500).send({
message: 'not authorized app'
});
}
});
});
}
});
});
So I login, I get asked to give permission to the application to use my account info, I get a json response where I can see my name, email and token, and that's it
Even within the company where I work, no one could find an answer. So I came with a solution myself. I don't use satellizer anymore.
.when('/access_token=:access_token', {
template: '',
controller: function($window, $http, $location, $rootScope) {
var hash = $location.path().substr(1);
var splitted = hash.split('&');
var params = {};
for (var i = 0; i < splitted.length; i++) {
var param = splitted[i].split('=');
var key = param[0];
var value = param[1];
params[key] = value;
$rootScope.accesstoken = params;
}
console.log(params.access_token);
var json = {
Token: params.access_token
};
$window.localStorage['token'] = params.access_token;
$http.post('http://localhost:3000/api/users/signIn', json).success(function(data, status) {
console.log(data);
}).error(function(err) {
console.log(err);
});
$location.path("/home");
}
/*controller: 'createNewsFeed',
templateUrl: 'homepage.html'*/
}).
So redirect the page by itself. Because the authentication works on the backend side, I can get a access token, which is the only thing I really need for future use of my rest api. I defined a route where, after receiving the json with the token, my browser is manually redirected to with $window.location. So when that page is loaded (not visible for the user, it goes too fast to notice) I analyse the token, save the token, analyse authentication, when that is successful I manually redirect to the homepage.
I have an angular-fullstack app generated from here -
https://github.com/angular-fullstack/generator-angular-fullstack
I am using the same directory structure as angular-fullstack.
Now I am trying to authenticate users with facebook sdk and did the following steps -
1) specify passport facebook login strategy
// created auth/facebook/index.js
'use strict';
var express = require('express');
var passport = require('passport');
var auth = require('../auth.service');
var router = express.Router();
router
.get('/', passport.authenticate('facebook', {
scope: ['email', 'public_profile', 'user_friends', 'user_events'],
failureRedirect: '/',
session: false
}))
.get('/callback', passport.authenticate('facebook', {
failureRedirect: '/',
session: false
}), auth.setTokenCookie);
module.exports = router;
// created auth/facebook/passport.js
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
var config = require('../../config/environment');
var jwt = require('jsonwebtoken');
exports.setup = function (User, config) {
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
},
function(accessToken, refreshToken, profile, done) {
User.findOne({'facebookId':profile.id}, function(err, user){
if(err) return done(err);
if(user) {
return done(null, user);
} else {
var newUser = {};
newUser['facebookId'] = profile.id;
newUser['providerData'] = {
name: 'facebook',
username: profile.username,
displayName: profile.displayName,
gender: profile.gender,
profileUrl: profile.profileUrl
};
newUser['name'] = profile.name.givenName ? profile.name.givenName: '';
newUser['email'] = profile.emails.length>0? profile.emails[0].value : done('email not found');
function generatePassword() {
var length = 8,
charset = "abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
retVal = "";
for (var i = 0, n = charset.length; i < length; ++i) {
retVal += charset.charAt(Math.floor(Math.random() * n));
}
return retVal;
}
newUser['password'] = generatePassword();
newUser['role'] = 'user';
var user = new User(newUser);
user.save(function (err, user) {
if (err) { console.log(err); done(err); }
var token = jwt.sign({_id: user._id }, config.secrets.session, { expiresInMinutes: 60 * 5 });
res.json({ token: token });
});
}
});
}
));
};
// added entry in auth/index.js for facebook module
'use strict';
var express = require('express');
var passport = require('passport');
var config = require('../config/environment');
var User = require('../api/user/user.model');
// Passport Configuration
require('./local/passport').setup(User, config);
require('./facebook/passport').setup(User, config);
var router = express.Router();
router.use('/local', require('./local'));
router.use('/facebook', require('./facebook'));
module.exports = router;
In client side I made the following changes -
// installed ng-facebook from https://github.com/GoDisco/ngFacebook using bower install ng-facebook
// added ngFacebook in Angular App module
// set App Id in app.config -
$facebookProvider.setAppId('XXXXXXXXXXXX');
Then added this - in app.run
app.run(function ($rootScope, $location, Auth) {
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
// Redirect to login if route requires auth and you're not logged in
$rootScope.$on('$stateChangeStart', function (event, next) {
Auth.isLoggedInAsync(function (loggedIn) {
if (next.authenticate && !loggedIn) {
$location.path('/access/signin');
}
});
});
})
Then finally calling /auth/facebook from my client now I am getting the data from facebook after a user logs in and I am able to save it in Database, but the homepage always gets redirected to login state and not the dashboard.
I have the following http interceptors in my client app -
app.factory('authInterceptor', function ($rootScope, $q, $cookieStore) {
return {
// Add authorization token to headers
request: function (config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
},
// Intercept 401s and redirect you to login
responseError: function (response) {
if (response.status === 401) {
$cookieStore.remove('token');
return $q.reject(response);
}
else if (response.status === 403) {
$cookieStore.remove('token');
return $q.reject(response);
} else if (response.status === 405) {
$cookieStore.remove('token');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
};
})
Now after I login with my facebook account, when I receive the callback from facebook. It is getting redirected to the same login state again even when the API /api/users/me is giving me the logged in information in my browser console -
{"_id":"569bc8d6b0c2e8315539539e","facebookId":"XXXXX","name":"Harshit","email":"XXXX","__v":0,"providerData":{"name":"facebook"},"messages":[],"notifications":[],"subjects":[],"date":"2016-01-17T17:01:10.000Z","role":["user"]}
So, I am thinking passport is not setting the authorization headers properly or there is something other than my http interceptor that is redirecting me to the login page only
How can I debug this issue or find out where I am going wrong, or missing something ?
In my opinion I prefer just checking whether the server still has your sesssion information.
In your routing you can do check
when('/url', {
templateUrl: 'partial',
controller: 'controller',
resolve: { loggedin: checkLoggedin}}).
Just create your function checkLoggedin like this
var checkLoggedin = function($q, $http, $location){
var deferred = $q.defer();
$http.get('/loggedin').then(function(response){
deferred.resolve();
},function(response){
deferred.reject();
$location.path('/home');
});
return deferred.promise;
}
Basically your making a promise here. Your saying here go to the backend and check I will wait for the backend to send me back a response. If the response is 200 let them on the page or else redirect to home.
Your back-end should return a 401 (unauthorize) or 200 (success) response letting your front-end know whether to let the user on the page.
function(req,res){
if (req.isAuthenticated() == true) {
res.status(200).send("Authenticate.");
}else{
res.status(401).send("Not Authenticate");
}
}
You can check more info about resolve here
Angular Route Provider
The resolve will run all dependencies that is passed to it before loading your view.
This will allow you to make a http request to your back end and verify with passport to see if the session is still there.
Angular has to make a http request to the backend everytime to make sure that the user is indeed logged in.
I am trying to implement a persistent login for an angular application. By persistent I mean I am able to redirect to a new page or refresh without being logged out.
Looking at the debugger it does not appear that my /api/users route is ever being hit. api/sessions is and im not sure why the other one wouldn't be.
my code is:
routes.js
app.post('/api/sessions', function(req, res, next) {
User.findOne({username: req.body.username})
.select('password').select('username')
.exec( function(err, user){
if (err) {return next(err)}
if (!user) {return res.send(401)}
bcrypt.compare(req.body.password, user.password, function (err, valid){
if (err) {return next(err)}
if (!valid) {return res.send(401)}
var token = jwt.encode({username: user.username}, config.secret)
res.send(token)
})
})
})
app.get('/api/users', function(req, res, next) {
if(!req.headers['x-auth']){
return res.send(401)
}
var auth = jwt.decode(req.headers['x-auth'], config.secret)
User.findOne({username: auth.username}, function (err,user){
if (err) {return next(err)}
res.json(user)
})
})
app.post('/api/users', function(req, res, next) {
var user = new User({username: req.body.username})
bcrypt.hash(req.body.password, 10, function (err, hash){
if (err) {return next (err)}
user.password = hash
user.save(function (err){
res.send(201)
})
})
})
angular.js
app.service('UserSvc', function($http, $window){
var svc = this;
svc.getUser = function() {
return $http.get('/api/users',{
headers: { 'X-Auth': this.token }
})
}
svc.login = function(username, password){
return $http.post('/api/sessions', {
username: username, password: password
}).then(function(val){
svc.token = val.data
// window.localStorage.token = val.data
return svc.getUser()
})
}
svc.logout = function() {
$http.post('/api/sessions', {
username: null, password: null
}).then(function(val){
svc.token = null
// window.localStorage.token = val.data
})
}
})
app.controller('LoginCtrl', function($scope, $location, UserSvc){
$scope.login = function(username, password) {
UserSvc.login(username, password)
.then(function(response) {
$scope.$emit('login', response.data)
$location.path('/dashboard');
})
}
$scope.logout = function() {
UserSvc.logout();
$scope.$emit('logout')
}
});
app.controller('ApplicationCtrl', function($scope, UserSvc) {
angular.element(document).ready(function () {
$scope.currentUser = UserSvc.getUser();
})
$scope.modalShown = true;
$scope.$on('login', function (_, user){
$scope.currentUser = user;
})
$scope.$on('logout', function (){
$scope.currentUser = null;
})
});
if anyone has any pointers please let me know! I have spent way to much time on this :(
I believe the problem is rather simple here.
Services need to be instantiated (with new UserSvc).
Factories do not. So if you wanted it to use it the way you are, change UserSvc to be a factory and have it return svc.
Other thing to note would be that Factories/Services are singletons, so returning the svc, along with a variable holding the resultant user object will persist through angular router traversal but not on a page refresh. For that you would want to store the user in sessionStorage on the client (or in localStorage with some sort of timeout).
how do i post html login form to php login form in a different url using angular js controller and returning success when the login credential is correct and failure when the credentials are wrong.below is my existing Controller and intends to use it together with my html login page while it posts/authenticates the login.php and returns success or failure upon input credentials
.controller('LoginCtrl', function ($scope, $state, $ionicViewService, $http, DataStore) {
$scope.domain = DataStore.domain;
var urlpath = DataStore.domain+'/login.php';
$("#username").focus();
$("#username, #password").keyup(function () {
if ($(this).val().length !== 0) {
$("#validate").hide();
}
});
//Authenticates blank fields
$("#login").on('click', function () {
if ($("#username").val() == '') {
$("#validate").html("username is required").show();
$("#username").focus();
}
else if ($("#password").val() == '') {
$("#validate").html("Password is required").show();
$("#password").focus();
}
else {
$.ajax({
type: "POST",
url: urlpath,
data: $('#myloginform').serialize(),
success: function (html) {
var resp = html.split(":");
// alert(resp[0]);
if (resp[0] == 'success') {
$("#validate").html("Wrong username or password").show();
}else {
$state.go('menu.home');
}
}
});
// todo: Login is actually done here
//todo: validate the login
$ionicViewService.nextViewOptions({
disableBack: true
});
//$state.go('menu.home');
return false;
};
})
})
Have you tried coding an
else {
$http.post('http://localhost:0000', data).success(successCallback);
}
Localhost would be the ip or url of the server you are wishing to send the post data to.