我正在写一个小的AngularJS应用程序,它有一个登录视图和一个主视图,配置如下:
$routeProvider
.when('/main' , {templateUrl: 'partials/main.html', controller: MainController})
.when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
.otherwise({redirectTo: '/login'});
我的LoginController检查user/pass组合,并在$rootScope上设置一个属性:
function LoginController($scope, $location, $rootScope) {
$scope.attemptLogin = function() {
if ( $scope.username == $scope.password ) { // test
$rootScope.loggedUser = $scope.username;
$location.path( "/main" );
} else {
$scope.loginError = "Invalid user/pass.";
}
}
一切正常,但如果我访问http://localhost/#/main,我最终绕过了登录屏幕。我想写一些类似于“每当路由改变,如果$rootScope。loggedUser为空,然后重定向到/login"
...
... 等待。我能以某种方式听到路线变化吗?不管怎样,我会把这个问题发布出来,继续寻找。
使用angular-ui-router可以重定向到另一个视图。为此,我们使用了$state.go("target_view")方法。例如:
---- app.js -----
var app = angular.module('myApp', ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider) {
// Otherwise
$urlRouterProvider.otherwise("/");
$stateProvider
// Index will decide if redirects to Login or Dashboard view
.state("index", {
url: ""
controller: 'index_controller'
})
.state('dashboard', {
url: "/dashboard",
controller: 'dashboard_controller',
templateUrl: "views/dashboard.html"
})
.state('login', {
url: "/login",
controller: 'login_controller',
templateUrl: "views/login.html"
});
});
// Associate the $state variable with $rootScope in order to use it with any controller
app.run(function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
});
app.controller('index_controller', function ($scope, $log) {
/* Check if the user is logged prior to use the next code */
if (!isLoggedUser) {
$log.log("user not logged, redirecting to Login view");
// Redirect to Login view
$scope.$state.go("login");
} else {
// Redirect to dashboard view
$scope.$state.go("dashboard");
}
});
----- HTML -----
<!DOCTYPE html>
<html>
<head>
<title>My WebSite</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="MyContent">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="js/libs/angular.min.js" type="text/javascript"></script>
<script src="js/libs/angular-ui-router.min.js" type="text/javascript"></script>
<script src="js/app.js" type="text/javascript"></script>
</head>
<body ng-app="myApp">
<div ui-view></div>
</body>
</html>
1. 设置全局当前用户。
在身份验证服务中,将当前经过身份验证的用户设置为根作用域。
// AuthService.js
// auth successful
$rootScope.user = user
2. 在每条受保护路由上设置认证功能。
// AdminController.js
.config(function ($routeProvider) {
$routeProvider.when('/admin', {
controller: 'AdminController',
auth: function (user) {
return user && user.isAdmin
}
})
})
3.检查每个路由更改的认证。
// index.js
.run(function ($rootScope, $location) {
$rootScope.$on('$routeChangeStart', function (ev, next, curr) {
if (next.$$route) {
var user = $rootScope.user
var auth = next.$$route.auth
if (auth && !auth(user)) { $location.path('/') }
}
})
})
或者,您可以在用户对象上设置权限并为每个路由分配权限,然后在事件回调中检查权限。
如果你不想使用angular-ui-router,但想让你的控制器通过RequireJS惰性加载,当你使用你的控制器作为RequireJS模块(惰性加载)时,事件$routeChangeStart会有几个问题。
你不能确定控制器会在$ routechangstart被触发之前被加载——事实上它不会被加载。这意味着您不能访问下一个路由的属性,如locals或$$route,因为它们还没有设置。
例子:
app.config(["$routeProvider", function($routeProvider) {
$routeProvider.when("/foo", {
controller: "Foo",
resolve: {
controller: ["$q", function($q) {
var deferred = $q.defer();
require(["path/to/controller/Foo"], function(Foo) {
// now controller is loaded
deferred.resolve();
});
return deferred.promise;
}]
}
});
}]);
app.run(["$rootScope", function($rootScope) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
console.log(next.$$route, next.locals); // undefined, undefined
});
}]);
这意味着您不能检查其中的访问权限。
解决方案:
由于控制器的加载是通过resolve完成的,你可以对你的访问控制检查做同样的事情:
app.config(["$routeProvider", function($routeProvider) {
$routeProvider.when("/foo", {
controller: "Foo",
resolve: {
controller: ["$q", function($q) {
var deferred = $q.defer();
require(["path/to/controller/Foo"], function(Foo) {
// now controller is loaded
deferred.resolve();
});
return deferred.promise;
}],
access: ["$q", function($q) {
var deferred = $q.defer();
if (/* some logic to determine access is granted */) {
deferred.resolve();
} else {
deferred.reject("You have no access rights to go there");
}
return deferred.promise;
}],
}
});
}]);
app.run(["$rootScope", function($rootScope) {
$rootScope.$on("$routeChangeError", function(event, next, current, error) {
console.log("Error: " + error); // "Error: You have no access rights to go there"
});
}]);
注意,这里不是使用事件$routeChangeStart,而是使用$routeChangeError