3 回答
TA贡献1876条经验 获得超5个赞
这是另一种可能的解决方案,使用或的resolve
属性。示例:$stateProvider
$routeProvider
$stateProvider
.config(["$stateProvider", function ($stateProvider) { $stateProvider .state("forbidden", { /* ... */ }) .state("signIn", { /* ... */ resolve: { access: ["Access", function (Access) { return Access.isAnonymous(); }], } }) .state("home", { /* ... */ resolve: { access: ["Access", function (Access) { return Access.isAuthenticated(); }], } }) .state("admin", { /* ... */ resolve: { access: ["Access", function (Access) { return Access.hasRole("ROLE_ADMIN"); }], } });}])
Access
根据当前用户权限解析或拒绝承诺:
.factory("Access", ["$q", "UserProfile", function ($q, UserProfile) { var Access = { OK: 200, // "we don't know who you are, so we can't say if you're authorized to access // this resource or not yet, please sign in first" UNAUTHORIZED: 401, // "we know who you are, and your profile does not allow you to access this resource" FORBIDDEN: 403, hasRole: function (role) { return UserProfile.then(function (userProfile) { if (userProfile.$hasRole(role)) { return Access.OK; } else if (userProfile.$isAnonymous()) { return $q.reject(Access.UNAUTHORIZED); } else { return $q.reject(Access.FORBIDDEN); } }); }, hasAnyRole: function (roles) { return UserProfile.then(function (userProfile) { if (userProfile.$hasAnyRole(roles)) { return Access.OK; } else if (userProfile.$isAnonymous()) { return $q.reject(Access.UNAUTHORIZED); } else { return $q.reject(Access.FORBIDDEN); } }); }, isAnonymous: function () { return UserProfile.then(function (userProfile) { if (userProfile.$isAnonymous()) { return Access.OK; } else { return $q.reject(Access.FORBIDDEN); } }); }, isAuthenticated: function () { return UserProfile.then(function (userProfile) { if (userProfile.$isAuthenticated()) { return Access.OK; } else { return $q.reject(Access.UNAUTHORIZED); } }); } }; return Access;}])
UserProfile
将当前用户的属性,并执行$hasRole
,$hasAnyRole
,$isAnonymous
和$isAuthenticated
方法的逻辑(加上一个$refresh
方法,稍后解释):
.factory("UserProfile", ["Auth", function (Auth) { var userProfile = {}; var clearUserProfile = function () { for (var prop in userProfile) { if (userProfile.hasOwnProperty(prop)) { delete userProfile[prop]; } } }; var fetchUserProfile = function () { return Auth.getProfile().then(function (response) { clearUserProfile(); return angular.extend(userProfile, response.data, { $refresh: fetchUserProfile, $hasRole: function (role) { return userProfile.roles.indexOf(role) >= 0; }, $hasAnyRole: function (roles) { return !!userProfile.roles.filter(function (role) { return roles.indexOf(role) >= 0; }).length; }, $isAnonymous: function () { return userProfile.anonymous; }, $isAuthenticated: function () { return !userProfile.anonymous; } }); }); }; return fetchUserProfile();}])
Auth
负责请求服务器,知道用户配置文件(例如链接到附加到请求的访问令牌):
.service("Auth", ["$http", function ($http) { this.getProfile = function () { return $http.get("api/auth"); };}])
在请求时,服务器应返回此类JSON对象GET api/auth
:
{ "name": "John Doe", // plus any other user information "roles": ["ROLE_ADMIN", "ROLE_USER"], // or any other role (or no role at all, i.e. an empty array) "anonymous": false // or true}
最后,当Access
拒绝承诺时,如果使用ui.router
,$stateChangeError
则会触发该事件:
.run(["$rootScope", "Access", "$state", "$log", function ($rootScope, Access, $state, $log) { $rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) { switch (error) { case Access.UNAUTHORIZED: $state.go("signIn"); break; case Access.FORBIDDEN: $state.go("forbidden"); break; default: $log.warn("$stateChangeError event catched"); break; } });}])
如果使用ngRoute
,$routeChangeError
将触发该事件:
.run(["$rootScope", "Access", "$location", "$log", function ($rootScope, Access, $location, $log) { $rootScope.$on("$routeChangeError", function (event, current, previous, rejection) { switch (rejection) { case Access.UNAUTHORIZED: $location.path("/signin"); break; case Access.FORBIDDEN: $location.path("/forbidden"); break; default: $log.warn("$stateChangeError event catched"); break; } });}])
也可以在控制器中访问用户配置文件:
.state("home", { /* ... */ controller: "HomeController", resolve: { userProfile: "UserProfile" }})
UserProfile
然后包含服务器在请求时返回的属性GET api/auth
:
.controller("HomeController", ["$scope", "userProfile", function ($scope, userProfile) { $scope.title = "Hello " + userProfile.name; // "Hello John Doe" in the example}])
UserProfile
需要在用户登录或注销时刷新,以便Access
可以使用新的用户配置文件处理路由。您可以重新加载整个页面,也可以调用UserProfile.$refresh()
。登录时的示例:
.service("Auth", ["$http", function ($http) { /* ... */ this.signIn = function (credentials) { return $http.post("api/auth", credentials).then(function (response) { // authentication succeeded, store the response access token somewhere (if any) }); };}])
.state("signIn", { /* ... */ controller: "SignInController", resolve: { /* ... */ userProfile: "UserProfile" }})
.controller("SignInController", ["$scope", "$state", "Auth", "userProfile", function ($scope, $state, Auth, userProfile) { $scope.signIn = function () { Auth.signIn($scope.credentials).then(function () { // user successfully authenticated, refresh UserProfile return userProfile.$refresh(); }).then(function () { // UserProfile is refreshed, redirect user somewhere $state.go("home"); }); };}])
TA贡献2036条经验 获得超8个赞
为各个路由定义自定义行为的最简单方法相当简单:
1)routes.js
:requireAuth
为任何所需的路线创建一个新属性(如)
angular.module('yourApp').config(function($routeProvider) { $routeProvider .when('/home', { templateUrl: 'templates/home.html', requireAuth: true // our custom property }) .when('/login', { templateUrl: 'templates/login.html', }) .otherwise({ redirectTo: '/home' });})
2)在未绑定到内部元素的顶层控制器中ng-view
(为避免与角度冲突$routeProvider
),检查是否newUrl
具有requireAuth
属性并相应地采取相应措施
angular.module('YourApp').controller('YourController', function ($scope, $location, session) { // intercept the route change event $scope.$on('$routeChangeStart', function (angularEvent, newUrl) { // check if the custom property exist if (newUrl.requireAuth && !session.user) { // user isn’t authenticated $location.path("/login"); } }); });
添加回答
举报