身份验证 - 调用$ http的.then()成功回调而不是错误回调

时间:2015-12-14 21:28:51

标签: javascript angularjs authentication jwt angular-http-interceptors

这可能只是因为误解了如何在MEAN堆栈应用程序中进行最佳身份验证,或者我对promises和$ http .then()方法的工作方式缺乏了解,但每当我尝试对后端进行身份验证时节点服务器凭据不正确,它调用$ http的.then()方法的成功回调而不是错误回调。这是我的设置:

我正在使用jsonwebtokenexpress-jwt包,AngularJS拦截器添加要请求的令牌并检查状态401 responseErrors,设置/删除的TokenService等JWT和UserService处理登录,注销等。

从调试开始,这是正在发生的事情:

  1. 请求登录
  2. 服务器捕获请求,查找指定的用户,但无法在数据库中找到它们。使用JSON对象返回401错误,包括错误消息等
  3. HttpInterceptor使用responseError方法,正确地看到它是状态401,删除任何可能的现有令牌,重定向到/login屏幕,return s $q.reject(response)
  4. UserService.login()正确使用错误回调并执行return response
  5. 问题 - 我的login.js .login()方法中的成功回调运行,而不是第二个错误回调。我有一种感觉这与this article about promise chaining中讨论的内容有关,但我的专业知识在这里有其限制,我无法理解我接下来应该做什么来告诉链中的下一个回调前一个有错误......
  6. 这是我的设置:

    快递:

    authRoutes.js

    authRoutes.post("/login", function (req, res) {
    
        User.findOne({username: req.body.username}, function (err, user) {
            if (err) res.status(500).send(err);
            if (!user) {
                res.status(401).send({success: false, message: "User with the provided username was not found"})
            } else if (user) {
                bcrypt.compare(req.body.password, user.password, function (err, match) {
                    if (err) throw (err);
                    if (!match) res.status(401).json({success: false, message: "Incorrect password"});
                    else {
                        var token = jwt.sign(user, config.secret, {expiresIn: "24h"});
                        res.json({token: token, success: true, message: "Here's your token!"})
                    }
                });
            }
        });
    });
    

    从调试开始,当我使用不正确的凭据登录时,它正确地点击res.status(401).send(...)行,所以这部分似乎没问题。

    角:

    app.js(包括HttpInterceptor)

    var app = angular.module("TodoApp", ["ngRoute"]);
    
    app.factory("AuthInterceptor", ["$q", "$location", "TokenService", function ($q, $location, TokenService) {
        return {
            request: function (config) {
                var token = TokenService.getToken();
                if (token) {
                    config.headers = config.headers || {};
                    config.headers.Authorization = "Bearer " + token
                }
                return config;
            },
            responseError: function (response) {
                if (response.status === 401) {
                    TokenService.removeToken();
                    $location.path("/login");
                }
                return $q.reject(response);
            }
        }
    }]);
    
    app.config(function ($routeProvider, $httpProvider) {
        $httpProvider.interceptors.push('AuthInterceptor');
    
        $routeProvider
            .when("/", {
                templateUrl: "landing/landing-page.html"
            });
    });
    

    userService.js

    var app = angular.module("TodoApp");
    
    app.service("UserService", ["$http", "TokenService", function ($http, TokenService) {
    
        this.signup = function (user) {
            return $http.post("http://localhost:8080/auth/signup", user).then(function (response) {
                return response;
            }, function (response) {
                return response;
            });
        };
    
        this.login = function (user) {
            return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
                if (response.data.success) TokenService.setToken(response.data.token);
                return response;
            }, function (response) {
                return response;
            })
        };
    
        this.isAdmin = function (user) {
            return user.admin;
        };
    }]);
    

    login.js(问题似乎表现在哪里)

    var app = angular.module("TodoApp");
    
    app.config(function ($routeProvider) {
        $routeProvider
            .when("/login", {
                templateUrl: "auth/login.html",
                controller: "LoginController"
            })
    });
    
    app.controller("LoginController", ["$scope", "$http", "$location", "UserService", "TokenService", function ($scope, $http, $location, UserService, TokenService) {
    
        $scope.login = function (user) {
            UserService.login(user).then(function (response) {
                $location.path("/todo");
            }, function (response) {
                console.log("There was a problem: " + response);
            });
        }
    }]);
    

    最后一部分UserService.login(user).then(function (response) { $location.path("/todo");是正在运行并尝试将用户重定向到Todo项列表的行,当我希望运行console.log("There was a problem: " + response);时换行......

    就像我上面所说的那样,我有一种感觉,它与链接承诺有关,以及如何在链中途处理错误而不是在链中冒泡。不确定我是否需要添加.catch()块,就像上面提到的网站所说的那样。即使这是答案,我也不完全确定如何写出来。

    如果有更好的方法我应该组织这个,我也绝对愿意接受建议。我必须向一班学生讲授这一课,并希望确保我在教授良好实践。

    提前感谢您的帮助!

2 个答案:

答案 0 :(得分:8)

仔细查看代码的这一部分:

this.login = function (user) {
    return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
        if (response.data.success) TokenService.setToken(response.data.token);
        return response;
    }, function (response) {
        return response;
    })
}

这里你提供了一个带有返回值的错误回调,它返回到promise链中的下一个回调。您混淆的原因是,如果您希望错误进一步传播,您仍需要从回调中返回被拒绝的throw的promise。否则,它实际上意味着您已从错误情况恢复,并且流程中的下一步将成功。这就是你现在拥有的。

在您的情况下,您要么完全删除错误回调

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
});

...或确保您返回失败的承诺

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
}, function (response) {
    return $q.reject(response);
});

...或抛出:

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
}, function (response) {
    throw new Error(response);
});

答案 1 :(得分:1)

您是否曾尝试在$q.reject来电的错误案例中使用then()

E.g。

// remember to add $q to deps

this.login = function (user) {
    return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
        if (response.data.success) TokenService.setToken(response.data.token);
        return response;
    }, function (response) {
        $q.reject(response);
    })
};

相关文档:https://docs.angularjs.org/api/ng/service/$q