在继续之前,angularjs ui-router授权

时间:2014-06-23 17:55:14

标签: angularjs angular-ui-router

我有一个angularjs ui-router情况,其中:

  • 用户必须在点击任何页面之前获得授权
  • 如果用户已获得授权但没有路由,请重定向到其主页
  • 如果用户已获得授权并且有路线,则会重定向到路线
  • 如果用户已获得授权且没有路线且没有主页,请导航至默认页面
  • 如果用户未获得授权并且有路由,则重定向到登录页面,并在授权时重定向到该路由

这是一个棘手的情况,我似乎无法做到恰到好处。我当前的代码确实有效,但是......它必须显示“登录”#39;导航前一秒钟的页面。发生这种情况是因为我不得不以某种方式启动$stateChangeStart

var app = angular.module('myapp', ['ui.router']);

// handle default states based on authentication,
// default properties set in user profile, or
// or just redirect to 'apps' page
var authd = false, 
    defaultDashboard = undefined,
    defaultFn = function($injector){
        // required to get location since loaded before app
        var $location = $injector.get('$location');

        // if the user has a default dashboard, navigate to that
        if(defaultDashboard){
            $location.path('workspace/' + defaultDashboard);
        } else if(authd) {
            // if the user is auth'd but doesn't have url
            $location.path('home');
        } else {
            // if we aren't auth'd yet
            $location.path('login');
        }
    };

app.config(function ($urlRouterProvider, $locationProvider, $stateProvider) {
    $locationProvider.html5Mode(true);
    app.stateProvider = $stateProvider;

    $urlRouterProvider.otherwise(function($injector){
        defaultFn($injector);
    });
});

app.run(function ($rootScope, $q, $location, $state, $stateParams, $injector, security) {

    var deregister = $rootScope.$on("$stateChangeStart", function () {

        // authorize is a AJAX request to pass session token and return profile for user
        security.authorize().success(function(d){

            // set some local flags for defaultFn
            authd = true;
            defaultDashboard = d.defaultDashboard;

            // de-register the start event after login to prevent further calls
            deregister();

            // switch to default view after login
            if($location.$$url === "/login" || 
                    $location.$$url === "/"){
                defaultFn($injector);
            }

        }).error(function(){
            $location.path('login');
        });
    });
});

我使用一个接受器来处理401s,如:

var module = angular.module('security.interceptor', []);

// This http interceptor listens for authentication failures
module.factory('securityInterceptor', function($injector, $location) {
    return function(promise) {

        // Intercept failed requests
        return promise.then(null, function(originalResponse) {
            if(originalResponse.status === 401) {
                $location.path('/login');
            }

            return promise;
        });
    };
});

// We have to add the interceptor to the queue as a string because the 
// interceptor depends upon service instances that are not available in the config block.
module.config(function($httpProvider) {
    $httpProvider.defaults.withCredentials = true;
    $httpProvider.responseInterceptors.push('securityInterceptor');
});

任何人都有类似的案例并找到了更好的解决方案吗?

1 个答案:

答案 0 :(得分:5)

我想出了我的解决方案:

app.config(function ($urlRouterProvider, $locationProvider, $stateProvider) {
    $locationProvider.html5Mode(true);

    // placeholder
    $stateProvider.state('welcome', {
        url: '/'
    });

    $urlRouterProvider.otherwise('404');
});

app.run(function ($rootScope, $q, $location, $state, $stateParams, security, $urlRouter) {

    var deregister = $rootScope.$on("$stateChangeStart", function (event) {
        // stop the change!
        event.preventDefault();

        security.authorize().success(function(d){
            // if we don't have a previous url
            if($location.$$url === "/" || $location.$$url === "/login"){

                // If user has a preset home
                if(d.defaultDashboard){
                    $location.path('workspace/' + d.defaultDashboard);
                } else {
                    $location.path('welcome');
                }
            } else {
                // if we do, then continue
                $urlRouter.sync();
            }
        }).error(function(){
            // redirect to home
            $location.path('login');
        });

        // deregister the listener
        deregister();
    });

});

基本上,为空路线创建空路线解决了我的问题。有趣。