身份验证在不应该返回“401(未经授权)”时返回

Authentication is returning "401 (Unauthorized)" when it shouldn't

我是第一次设置身份验证功能,在用户登录后我得到了一些意想不到的结果。一位同事给了我一个具有工作身份验证的应用程序来模拟我的应用程序,看起来一切都一样我做的是正确的。

我在前端、SailsJS 后端框架和 PassportJS 身份验证中间件上使用 AngularJS。

我的来源(目前)公开存储...后端 API 在 Github 此处 (API Github) and the front-end code is found here (Front-End Github)

基本上发生的是用户

  1. 点击登录按钮,触发此功能

    login: function (credentials) {
        return baseAuth.customPOST(credentials, 'login').then(function (user) {
            $log.debug('User logged in: ', user);
            isAuthenticated = true;
            return user;
        });
    },
    
  2. 该自定义 POST 的控制器逻辑是这样的

    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);
    
    },
    
  3. 在那一步中,护照应该做它的事情并登录用户

    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 }); }
        });
       }
     ));
    

在控制台中,我总是提示这是成功的。

控制台读取:

User logged in:  Object {firstName: "John", lastName: "Doe", email: "john_doe@work.com", activated: true, isUser: true…}
  1. 然后,我对发生的事情的理解变得有点模糊。我知道应用程序然后会尝试查看用户是否已通过身份验证。 IsAuthenticated 被触发,在 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;
    }
    
  2. 在后端UserController中命中这个动作

    isAuthenticated: function (req, res) {
       if (req.isAuthenticated() && req.user.isUser) { return res.json(req.user); }
       else { return res.send(401); }
    },
    

然后就失败了 :( GET http://localhost:1337/user/authenticated 401 (Unauthorized) req.isAuthenticated 和 req.user.isUser 都没有通过。我把它们分开单独测试了,都不是真的。 "isUser" 是我默认为 true 的值,因此它应该对数据库中的每个用户都是 true。req.isAuthenticated 也失败了,我不完全理解。

有人了解我的问题吗?我在这里做错了什么?

通常 401 'Unauthorized' 错误实际上指的是凭据错误而不是 403 错误,后者指的是真正的未经授权的错误(禁止),因此您应该先使用 Postman 检查您的客户端以对其进行测试,然后继续给客户。

不过,我强烈建议您从 github 项目中退出并使用本教程来实施您的 passport.js 身份验证,因为您只需要执行 2 行代码和一些配置而不是弄乱代码:https://www.bearfruit.org/2014/07/21/tutorial-easy-authentication-for-sails-js-apps/

由于 passport.js 使用策略的基本概念工作,您需要确保使用正确的策略进行身份验证。我在任何地方都看不到名为 '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 }); }
    });
   }
 ));

应该改为

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 }); }
    });
   }
 ));

还要确保您的用户的 isUser 标志设置为 true。

如果您的前端应用程序与后端应用程序的来源不同,the AJAX requests will not include the session cookiereq.isAuthenticated() 永远不会 returns 正确。

使用 withCredentials 选项强制执行。

$http({ withCredentials: true, ... })

Restangular 似乎使用相同的选项:

https://github.com/mgonto/restangular#setdefaulthttpfields

https://docs.angularjs.org/api/ng/service/$http#usage

编辑:您还应该检查 the server side configuration,正如 idbehold

所指出的

正如 Matan 所建议的,您真的应该尝试一下服务器端的 sails-generate-auth 生成器。

https://github.com/sails101/even-more-passport

https://github.com/kasperisager/sails-generate-auth