问题
I am setting up an authentication functionality for my first time and am getting some unexpected results after a user has been logged in. A colleague has given me an application with working authentication to model my application after and it seems like everything I have done is correct.
I am using AngularJS on the front-end, SailsJS back-end framework, and PassportJS authentication middleware.
My source is (for now) stored publicly... the backend API is on Github here (API Github) and the front-end code is found here (Front-End Github)
What basically happens is that the user
Hits the login button, which triggers this function
login: function (credentials) { return baseAuth.customPOST(credentials, 'login').then(function (user) { $log.debug('User logged in: ', user); isAuthenticated = true; return user; }); },
The controller logic for that customPOST is this
login: function (req, res, next) { passport.authenticate('local', function (err, user, info) { if (err) { return res.json(err); } else if (user) { req.logIn(user, function (err) { if (err) { return res.json(err); } return res.json(user); }); } else { return res.json(400, info); } })(req, res); },
In that step, passport should do its thing and login the user
passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' }, function(email, password, next) { User.findOne({ email: email }) .exec(function (err, user) { if (err) { return next(err); } if (user) { if (user.activated) { bcrypt.compare(password, user.password, function (err, valid) { if (err) { next(err); } if (valid) { return next(null, user, { message: 'Logged In' }); } else { return next(null, false, { message: 'Incorrect password'}); } }); } else { next(null, false, { message: 'User is not activated. Please contact admins.'}); } } else { next(null, false, { message: 'Could not find user with email ' + email }); } }); } ));
In the console, I always get that this is successful.
Console reads:
User logged in: Object {firstName: "John", lastName: "Doe", email: "john_doe@work.com", activated: true, isUser: true…}
Then, my understanding of what happens gets kind of fuzzy. I know the application then tries to see if the user is authenticated. IsAuthenticated gets triggered, which looks like this in AngularJS:
isAuthenticated: function (force) { var deferred = $q.defer(); if (isAuthenticated && currentUser) { deferred.resolve(currentUser); } else { return baseAuth.customGET('authenticated').then(function (user) { deferred.resolve(currentUser); isAuthenticated = true; currentUser = user; return user; }); } return deferred.promise; }
It hits this action in the backend UserController
isAuthenticated: function (req, res) { if (req.isAuthenticated() && req.user.isUser) { return res.json(req.user); } else { return res.send(401); } },
Then it fails :( GET http://localhost:1337/user/authenticated 401 (Unauthorized)
Neither req.isAuthenticated nor req.user.isUser pass. I have separated them out to individually test and neither of them are true. "isUser" is a value I default to true and is so it should be true for every single user in the db. req.isAuthenticated also fails, which I don't entirely understand.
Anyone have some insight into my problem? What I have I done wrong here?
回答1:
If your frontend application has as a different origin than your backend application the AJAX requests will not include the session cookie and req.isAuthenticated()
will never returns true.
Use the withCredentials options to force it.
$http({ withCredentials: true, ... })
It seems that Restangular uses the same options:
https://github.com/mgonto/restangular#setdefaulthttpfields
https://docs.angularjs.org/api/ng/service/$http#usage
Edit: You should also check the server side configuration as pointed out by idbehold
As suggested by Matan, you should really give a try to the sails-generate-auth generator on the server side.
https://github.com/sails101/even-more-passport
https://github.com/kasperisager/sails-generate-auth
回答2:
Usualy a 401 'Unauthorized' error actually refers to a credentials error rather than 403 error which refers to a real Unauthorized error(forbidden) so you should check your client with Postman first to test It and then move on to the client.
although, I would highly recommend that you will drop down from that github project and use this tutorial to implmenet your passport.js authentication as you only need to execute 2 lines of code and some configurations rather then get messy with the code: https://www.bearfruit.org/2014/07/21/tutorial-easy-authentication-for-sails-js-apps/
回答3:
Since passport.js
works using the underlying concept of strategies, you need to make sure that you authenticate using the right one. I don't see anywhere a strategy called 'user'
passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'password' },
function(email, password, next) {
User.findOne({ email: email })
.exec(function (err, user) {
if (err) { return next(err); }
if (user) {
if (user.activated) {
bcrypt.compare(password, user.password, function (err, valid) {
if (err) { next(err); }
if (valid) {
return next(null, user, { message: 'Logged In' });
} else { return next(null, false, { message: 'Incorrect password'}); }
});
} else { next(null, false, { message: 'User is not activated. Please contact admins.'}); }
} else { next(null, false, { message: 'Could not find user with email ' + email }); }
});
}
));
should be changed to
passport.use('user', new LocalStrategy({ usernameField: 'email', passwordField: 'password' },
function(email, password, next) {
User.findOne({ email: email })
.exec(function (err, user) {
if (err) { return next(err); }
if (user) {
if (user.activated) {
bcrypt.compare(password, user.password, function (err, valid) {
if (err) { next(err); }
if (valid) {
return next(null, user, { message: 'Logged In' });
} else { return next(null, false, { message: 'Incorrect password'}); }
});
} else { next(null, false, { message: 'User is not activated. Please contact admins.'}); }
} else { next(null, false, { message: 'Could not find user with email ' + email }); }
});
}
));
Also make sure your user's isUser
flag is set to true.
来源:https://stackoverflow.com/questions/31082887/authentication-is-returning-401-unauthorized-when-it-shouldnt