如何使用ui-router检查身份验证并自动重定向到登录状态?

3

我在运行AngularJS v1.2.26时,在我的run中有一个函数。

.run(function(....) {
    authService.authCheck();

    $rootScope.$on('$routeChangeStart', function(event, next, current) {
        if (next.requireLogin) {
            if (!authService.isLoggedIn()) {
                $location.path('/login');
                event.preventDefault();
            }
        }
    });

})...

当直接访问需要身份验证的URL时,例如http://127.0.0.1:8080/secret,该函数始终重定向到登录路径。在调试一段时间后,发现它总是返回false。但当访问默认页面并转到指定路径时,则没有任何问题。

这是我的authService的一部分。

this.authCheck = function() {
    $http({
        method: 'PUT',
        url: '/api/login'
    }).
    success(function(data, status, headers, config) {
        if (status === 200) {
            userIsAuthenticated = true;
        } else {
            userIsAuthenticated = false;
        }
        $rootScope.loginStatus = userIsAuthenticated;
    }).
    error(function(data, status, headers, config) {
        userIsAuthenticated = false;
        $rootScope.loginStatus = userIsAuthenticated;
    });
};

this.isLoggedIn = function() {
    return userIsAuthenticated;
};

每当我在!authService.isLoggedIn()设置断点时,即使在运行块中尝试在到达$rootScope.$on函数之前进行身份验证,它也会评估为false。
那么,究竟是什么阻止了userIsAuthenticated变量的状态持久性呢?
2个回答

6
您的 authService 中的 .authCheck 是异步的,这意味着直到第一次完成检查后,userIsAuthenticated 才会设置为 true。如果您按照当前的路线,您将不得不编写一些更复杂的代码来等待检查是否已经完成,然后再进行重定向。然而,这是一个混乱的次优选项。
在这里最好的方法是让 ui-router 为您解决这个问题。为所有需要登录的状态创建一个共同的祖先状态,例如 'session'。然后使用 resolve 选项使该状态的解析等待您的身份验证检查。如果未经过身份验证,则创建特定的状态转移拒绝错误,您可以在其他地方捕获并采取行动(重定向到登录)。
.state('session', {
    resolve: {
        authentication: ['authService', '$q', function (authService, $q) {
            return authService.checkAuthentication().then(function () {
                if (!authService.isAuthenticated) {
                    return $q.reject({
                        notAuthenticated: true
                    });
                }
            });
        }]
    },
    // ...
})
.state('secret', {
    parent: 'session',
    // ...
});

然后

$rootScope.$on('$stateChangeError', function (_0, _1, _2, _3, _4, error) {
    if (error.notAuthenticated) {
        $state.go('login');
    }
});

(您还需要正确返回身份验证检查结果)
checkAuthentication: function () {
    return $http({...})
        .success(...)
        .error(...);
}

即使我没有使用 Promises,那个调用($http)仍然被认为是异步调用吗?感谢代码片段,我回家后会试一下。 - ymg
$http 调用始终是异步的,以防止浏览器锁定。而且你正在使用 promises - 返回值是一个扩展了特殊函数 successerror 的 promise :) 为了使我的示例工作,你只需要将整个东西返回即可。 - hon2a

0

你允许应用程序从 /secret 发送请求了吗? 这可能会阻止你从那里发送任何请求,因此它会将你重定向到登录页面


/secret 只是检查具有正确权限的身份验证令牌(会话)。问题在于我可以访问 /secret 并从那里发布有效表单,而服务器也没有问题,但是初始请求导致了问题,就像我所说的那样。 - ymg
我明白问题出在认证完成之前应用程序更改了根路径!你可以通过使用服务来触发$ routeChangeStart事件中的代码绕过此问题,而无需使用它(如果你必须尽快完成此功能,则这是最快的解决方案)。 - Utku Apaydin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接