3 回答

TA貢獻1876條經(jīng)驗 獲得超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
根據(jù)當前用戶權(quán)限解析或拒絕承諾:
.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
將當前用戶的屬性,并執(zhí)行$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
負責(zé)請求服務(wù)器,知道用戶配置文件(例如鏈接到附加到請求的訪問令牌):
.service("Auth", ["$http", function ($http) { this.getProfile = function () { return $http.get("api/auth"); };}])
在請求時,服務(wù)器應(yīng)返回此類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
則會觸發(fā)該事件:
.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
將觸發(fā)該事件:
.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
然后包含服務(wù)器在請求時返回的屬性GET api/auth
:
.controller("HomeController", ["$scope", "userProfile", function ($scope, userProfile) { $scope.title = "Hello " + userProfile.name; // "Hello John Doe" in the example}])
UserProfile
需要在用戶登錄或注銷時刷新,以便Access
可以使用新的用戶配置文件處理路由。您可以重新加載整個頁面,也可以調(diào)用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條經(jīng)驗 獲得超8個贊
為各個路由定義自定義行為的最簡單方法相當簡單:
1)routes.js
:requireAuth
為任何所需的路線創(chuàng)建一個新屬性(如)
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)在未綁定到內(nèi)部元素的頂層控制器中ng-view
(為避免與角度沖突$routeProvider
),檢查是否newUrl
具有requireAuth
屬性并相應(yīng)地采取相應(yīng)措施
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"); } }); });
添加回答
舉報