验证 AngularJS 状态更改时的登录效果不佳
Verify login on state change in AngularJS doesn't work well
我想在用户到达之前验证用户是否可以访问状态,如果他没有权限将被重定向到另一个页面。
问题是我正在做一个 SPA 并且它验证权限,但是在服务器发送响应并且用户被重定向之前需要一段时间,所以发生的事情是屏幕出现 1 或 2 秒然后被重定向成功地。有没有办法避免这种情况?
这是状态更改的代码:
webApp.run(function ($rootScope, $state, StateService) {
$rootScope.$on('$stateChangeStart', function (event, toState, fromState, toParams) {
StateService.hasAccessTo(toState.name, function(data){
if (data.data != ""){
event.preventDefault();
$state.go(data.data);
}
});
});
});
和服务:
webApp.service('StateService', function($http, $rootScope){
this.hasAccessTo = function(state, callback){
$http.get("state/" + state).then(callback);
}
});
我也试过 $stateChangeStart
中的 promise,但没用。
我读到了拦截器,但如果用户在另一个页面并访问我的拦截器,它们就会起作用,如果他已经在页面上并手动输入 link 它不会拦截。
欢迎任何新想法或改进的修改或建议!
编辑
现在我有了这个:
var hasAccessVerification = ['$q', 'StateService', function ($q, $state, StateService) {
var deferred = $q.defer();
StateService.hasAccessTo(this.name, function (data) {
if (data.data !== '') {
$state.go(data.data);
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}];
$urlRouterProvider.otherwise("/");
$compileProvider.debugInfoEnabled(false);
$stateProvider
.state('welcome',{
url:"/",
views: {
'form-view': {
templateUrl: '/partials/form.html',
controller: 'Controller as ctrl'
},
'@': {
templateUrl: '/partials/welcome.html'
}
},
data: {
requireLogin: false
},
resolve: {
hasAccess: hasAccessVerification
}
})
它会验证,但不会加载模板。它不显示 de views。我可能做错了什么?
编辑 2
我忘了在这里添加 $state:
var hasAccessVerification = ['$q', '$state', 'StateService', function ($q, $state, StateService){...}
考虑在您的状态配置中使用 resolve
而不是使用 $stateChangeStart
事件。
根据文档:
If any of these dependencies are promises, they will be resolved and
converted to a value before the controller is instantiated and the
$stateChangeSuccess
event is fired.
示例:
var hasAccessFooFunction = ['$q', 'StateService', function ($q, StateService) {
var deferred = $q.defer();
StateService.hasAccessTo(this.name, function (data) {
if (data.data !== '') {
$state.go(data.data);
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}];
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard.html',
resolve: {
hasAccessFoo: hasAccessFooFunction
}
})
.state('user', {
abstract: true,
url: '/user',
resolve: {
hasAccessFoo: hasAccessFooFunction
},
template: '<ui-view/>'
})
.state('user.create', {
url: '/create',
templateUrl: 'views/user/create.html'
})
.state('user.list', {
url: '/list',
templateUrl: 'views/user/list.html'
})
.state('user.edit', {
url: '/:id',
templateUrl: 'views/user/edit.html'
})
.state('visitors', {
url: '/gram-panchayat',
resolve: {
hasAccessFoo: hasAccessFooFunction
},
templateUrl: 'views/visitor/list.html'
});
并且根据文档 https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#inherited-resolved-dependencies resolve
是继承的:
New in version 0.2.0
Child states will inherit resolved dependencies from parent state(s),
which they can overwrite. You can then inject resolved dependencies
into the controllers and resolve functions of child states.
但是,请注意:
The resolve
keyword MUST be on the state not the views (in case you
use multiple views).
最佳做法是在 responseError
上设置 interceptor
,它会检查响应状态并采取相应措施:
webApp.config(['$httpProvider' ($httpProvider) {
var interceptor = ['$q', '$rootScope', function ($q, $rootScope) {
return {
request: function (config) {
// can also do something here
// for example, add token header
return config;
},
'responseError': function (rejection) {
if (rejection.status == 401 && rejection.config.url !== '/url/to/login') {
// If we're not on the login page
$rootScope.$broadcast('auth:loginRequired');
}
}
return $q.reject(rejection);
}
}
}];
$httpProvider.interceptors.push(interceptor);
}]);
并在 run
块中处理重定向
webApp.run(['$rootScope', function($rootScope){
$rootScope.$on('auth:loginRequired', function () {
$state.go('loginState');
});
}]);
好处是$state
服务不需要处理权限逻辑:
$stateProvider
.state('someState', {
url: '/some-state',
templateUrl: '/some-state.html',
resolve: {
dataFromBackend: ['dataService', function (postingService) {
// if the request fails, the user gets redirected
return dataService.getData();
}],
},
controller: function ($scope, dataFromBackend) {
}
})
通知
使用这种方法,您不需要 StateService
,您需要做的就是 return 来自后端的正确响应状态。例如,如果用户是访客,则 return 401
status.
我想在用户到达之前验证用户是否可以访问状态,如果他没有权限将被重定向到另一个页面。 问题是我正在做一个 SPA 并且它验证权限,但是在服务器发送响应并且用户被重定向之前需要一段时间,所以发生的事情是屏幕出现 1 或 2 秒然后被重定向成功地。有没有办法避免这种情况?
这是状态更改的代码:
webApp.run(function ($rootScope, $state, StateService) {
$rootScope.$on('$stateChangeStart', function (event, toState, fromState, toParams) {
StateService.hasAccessTo(toState.name, function(data){
if (data.data != ""){
event.preventDefault();
$state.go(data.data);
}
});
});
});
和服务:
webApp.service('StateService', function($http, $rootScope){
this.hasAccessTo = function(state, callback){
$http.get("state/" + state).then(callback);
}
});
我也试过 $stateChangeStart
中的 promise,但没用。
我读到了拦截器,但如果用户在另一个页面并访问我的拦截器,它们就会起作用,如果他已经在页面上并手动输入 link 它不会拦截。
欢迎任何新想法或改进的修改或建议!
编辑
现在我有了这个:
var hasAccessVerification = ['$q', 'StateService', function ($q, $state, StateService) {
var deferred = $q.defer();
StateService.hasAccessTo(this.name, function (data) {
if (data.data !== '') {
$state.go(data.data);
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}];
$urlRouterProvider.otherwise("/");
$compileProvider.debugInfoEnabled(false);
$stateProvider
.state('welcome',{
url:"/",
views: {
'form-view': {
templateUrl: '/partials/form.html',
controller: 'Controller as ctrl'
},
'@': {
templateUrl: '/partials/welcome.html'
}
},
data: {
requireLogin: false
},
resolve: {
hasAccess: hasAccessVerification
}
})
它会验证,但不会加载模板。它不显示 de views。我可能做错了什么?
编辑 2
我忘了在这里添加 $state:
var hasAccessVerification = ['$q', '$state', 'StateService', function ($q, $state, StateService){...}
考虑在您的状态配置中使用 resolve
而不是使用 $stateChangeStart
事件。
根据文档:
If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the
$stateChangeSuccess
event is fired.
示例:
var hasAccessFooFunction = ['$q', 'StateService', function ($q, StateService) {
var deferred = $q.defer();
StateService.hasAccessTo(this.name, function (data) {
if (data.data !== '') {
$state.go(data.data);
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}];
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'views/dashboard.html',
resolve: {
hasAccessFoo: hasAccessFooFunction
}
})
.state('user', {
abstract: true,
url: '/user',
resolve: {
hasAccessFoo: hasAccessFooFunction
},
template: '<ui-view/>'
})
.state('user.create', {
url: '/create',
templateUrl: 'views/user/create.html'
})
.state('user.list', {
url: '/list',
templateUrl: 'views/user/list.html'
})
.state('user.edit', {
url: '/:id',
templateUrl: 'views/user/edit.html'
})
.state('visitors', {
url: '/gram-panchayat',
resolve: {
hasAccessFoo: hasAccessFooFunction
},
templateUrl: 'views/visitor/list.html'
});
并且根据文档 https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#inherited-resolved-dependencies resolve
是继承的:
New in version 0.2.0
Child states will inherit resolved dependencies from parent state(s), which they can overwrite. You can then inject resolved dependencies into the controllers and resolve functions of child states.
但是,请注意:
The
resolve
keyword MUST be on the state not the views (in case you use multiple views).
最佳做法是在 responseError
上设置 interceptor
,它会检查响应状态并采取相应措施:
webApp.config(['$httpProvider' ($httpProvider) {
var interceptor = ['$q', '$rootScope', function ($q, $rootScope) {
return {
request: function (config) {
// can also do something here
// for example, add token header
return config;
},
'responseError': function (rejection) {
if (rejection.status == 401 && rejection.config.url !== '/url/to/login') {
// If we're not on the login page
$rootScope.$broadcast('auth:loginRequired');
}
}
return $q.reject(rejection);
}
}
}];
$httpProvider.interceptors.push(interceptor);
}]);
并在 run
块中处理重定向
webApp.run(['$rootScope', function($rootScope){
$rootScope.$on('auth:loginRequired', function () {
$state.go('loginState');
});
}]);
好处是$state
服务不需要处理权限逻辑:
$stateProvider
.state('someState', {
url: '/some-state',
templateUrl: '/some-state.html',
resolve: {
dataFromBackend: ['dataService', function (postingService) {
// if the request fails, the user gets redirected
return dataService.getData();
}],
},
controller: function ($scope, dataFromBackend) {
}
})
通知
使用这种方法,您不需要 StateService
,您需要做的就是 return 来自后端的正确响应状态。例如,如果用户是访客,则 return 401
status.