Angular路由异步授权
Angular route async authorization
Angular 不提供任何 authorization/access 路由权限(我说的是默认 Angular 路由 1.x 而不是 beta 2.0 或 UI路线)。但我确实必须实施它。
我遇到的问题是我有一个调用服务器来提供此信息和 returns 承诺的服务。但是这个数据只是获取一次然后缓存在客户端,但是还是需要获取一次。
我现在想处理 $routeChangeStart
事件,检查下一条路线是否定义了特定的 属性 authorize: someRole
。然后,此处理程序应使用我之前提到的服务获取该数据,并对返回的数据采取相应的行动。
除了将 resolves 添加到我的所有路线之外,还有什么想法吗?我能以某种方式集中执行此操作吗?所有适用的路线一次?
最终解决方案
在接受的答案的帮助下,我能够实现一个相当简单且集中的解决方案来执行异步授权。 Click here 查看它的运行情况或检查其内部工作代码。
ui-router 有很多您可以轻松操作的事件。我一直在用它。
State Change Events 应有尽有。像这样的东西将在 AngularJS 2.x.
中实现
但是,如果您正在寻找本机 Angular 1.x.y 路由器的解决方案,则此解决方案对您没有帮助。抱歉
如果你可以使用 ui-router,你可以这样做:
.state('root', {
url: '',
abstract: true,
templateUrl: 'some-template.html',
resolve: {
user: ['Auth', function (Auth) {
return Auth.resolveUser();
}]
}
})
Auth.resolveUser()
只是加载当前用户的后端调用。它 returns 一个承诺,因此路由将在更改之前等待它加载。
路由是抽象的,因此其他控制器必须从它继承才能工作,而且您还有一个额外的好处,即所有子控制器都可以通过解析访问当前用户。
现在您在 app.run()
中捕获了 $stateChangeStart
事件:
$rootScope.$on('$stateChangeStart', function (event, next) {
if (!Auth.signedIn()) { //this operates on the already loaded user
//user not authenticated
// all controllers need authentication unless otherwise specified
if (!next.data || !next.data.anonymous) {
event.preventDefault();
$state.go('account.login');
}
}else{
//authenticated
// next.data.roles - this is a custom property on a route.
if(!Auth.hasRequiredRole(next.data.roles)){
event.preventDefault();
$state.go('account.my'); //or whatever
}
}
});
那么需要ui扮演角色的路由可以是这样的:
.state('root.dashboard', {
//it's a child of the *root* route
url: '/dashboard',
data: {
roles: ['manager', 'admin']
}
...
});
希望它有意义。
最简单的方法是处理当前路由的 resolve 依赖关系,$routeChangeStart
是管理它的好地方。 Here's an example.
app.run(function ($rootScope, $location) {
var unrestricted = ['', '/login'];
$rootScope.$on('$routeChangeStart', function (e, to) {
if (unrestricted.indexOf(to.originalPath) >= 0)
return;
to.resolve = to.resolve || {};
// can be overridden by route definition
to.resolve.auth = to.resolve.auth || 'authService';
});
$rootScope.$on('$routeChangeError', function (e, to, from, reason) {
if (reason.noAuth) {
// 'to' path and params should be passed to login as well
$location.path('/login');
}
});
});
另一种选择是将 default
方法添加到 $routeProvider
并修补 $routeProvider.when
以从默认对象扩展路由定义。
这个问题我已经处理过很多次了,我也开发了一个模块(github)。
我的模块(建立在 ui.router 之上)基于 $stateChangeStart(ui.router 事件),但概念与默认的 ng.route 模块相同,只是实现方式不同。
总而言之,我认为处理路由更改事件并不是执行身份验证检查的好方法:
例如,当我们需要通过 ajax 获取 acl 时,事件就帮不了我们了。
我认为一个好方法是自动为每个 "protected" 状态附加一个解析...
不幸的是,ui.Router 没有提供 API 来拦截状态创建,所以我在 $stateProvider.state 方法之上使用一些变通方法开始了我的模块返工。
毫无疑问,我正在寻找不同的意见,以便找到在 AngularJS 中实现身份验证服务的正确方法。
如果有人对这项研究感兴趣...请在我的 github 上开一个问题并讨论
Angular 不提供任何 authorization/access 路由权限(我说的是默认 Angular 路由 1.x 而不是 beta 2.0 或 UI路线)。但我确实必须实施它。
我遇到的问题是我有一个调用服务器来提供此信息和 returns 承诺的服务。但是这个数据只是获取一次然后缓存在客户端,但是还是需要获取一次。
我现在想处理 $routeChangeStart
事件,检查下一条路线是否定义了特定的 属性 authorize: someRole
。然后,此处理程序应使用我之前提到的服务获取该数据,并对返回的数据采取相应的行动。
除了将 resolves 添加到我的所有路线之外,还有什么想法吗?我能以某种方式集中执行此操作吗?所有适用的路线一次?
最终解决方案
在接受的答案的帮助下,我能够实现一个相当简单且集中的解决方案来执行异步授权。 Click here 查看它的运行情况或检查其内部工作代码。
ui-router 有很多您可以轻松操作的事件。我一直在用它。
State Change Events 应有尽有。像这样的东西将在 AngularJS 2.x.
中实现但是,如果您正在寻找本机 Angular 1.x.y 路由器的解决方案,则此解决方案对您没有帮助。抱歉
如果你可以使用 ui-router,你可以这样做:
.state('root', {
url: '',
abstract: true,
templateUrl: 'some-template.html',
resolve: {
user: ['Auth', function (Auth) {
return Auth.resolveUser();
}]
}
})
Auth.resolveUser()
只是加载当前用户的后端调用。它 returns 一个承诺,因此路由将在更改之前等待它加载。
路由是抽象的,因此其他控制器必须从它继承才能工作,而且您还有一个额外的好处,即所有子控制器都可以通过解析访问当前用户。
现在您在 app.run()
中捕获了 $stateChangeStart
事件:
$rootScope.$on('$stateChangeStart', function (event, next) {
if (!Auth.signedIn()) { //this operates on the already loaded user
//user not authenticated
// all controllers need authentication unless otherwise specified
if (!next.data || !next.data.anonymous) {
event.preventDefault();
$state.go('account.login');
}
}else{
//authenticated
// next.data.roles - this is a custom property on a route.
if(!Auth.hasRequiredRole(next.data.roles)){
event.preventDefault();
$state.go('account.my'); //or whatever
}
}
});
那么需要ui扮演角色的路由可以是这样的:
.state('root.dashboard', {
//it's a child of the *root* route
url: '/dashboard',
data: {
roles: ['manager', 'admin']
}
...
});
希望它有意义。
最简单的方法是处理当前路由的 resolve 依赖关系,$routeChangeStart
是管理它的好地方。 Here's an example.
app.run(function ($rootScope, $location) {
var unrestricted = ['', '/login'];
$rootScope.$on('$routeChangeStart', function (e, to) {
if (unrestricted.indexOf(to.originalPath) >= 0)
return;
to.resolve = to.resolve || {};
// can be overridden by route definition
to.resolve.auth = to.resolve.auth || 'authService';
});
$rootScope.$on('$routeChangeError', function (e, to, from, reason) {
if (reason.noAuth) {
// 'to' path and params should be passed to login as well
$location.path('/login');
}
});
});
另一种选择是将 default
方法添加到 $routeProvider
并修补 $routeProvider.when
以从默认对象扩展路由定义。
这个问题我已经处理过很多次了,我也开发了一个模块(github)。 我的模块(建立在 ui.router 之上)基于 $stateChangeStart(ui.router 事件),但概念与默认的 ng.route 模块相同,只是实现方式不同。
总而言之,我认为处理路由更改事件并不是执行身份验证检查的好方法: 例如,当我们需要通过 ajax 获取 acl 时,事件就帮不了我们了。
我认为一个好方法是自动为每个 "protected" 状态附加一个解析...
不幸的是,ui.Router 没有提供 API 来拦截状态创建,所以我在 $stateProvider.state 方法之上使用一些变通方法开始了我的模块返工。
毫无疑问,我正在寻找不同的意见,以便找到在 AngularJS 中实现身份验证服务的正确方法。
如果有人对这项研究感兴趣...请在我的 github 上开一个问题并讨论