[英]Handling authentication with angular front-end -> How to protect specific pages?
希望在Node.js中构建具有用户登录(身份验证)功能的Web应用程序,该应用程序具有3个非安全页面(/ home,/ contact,/ about)和一个安全页面(/ admin)。 顺便说一句,我一直在参考scotch.io Mean Machine书。
我遇到的问题是我已经将所有内容都构建好了,登录机制的工作原理是:登录时,我被定向到/ admin; 但是,当我不登录而进入URL中的/ admin时,仍可以访问该页面。 也就是说,我不确定将实际保护放在何处。
下面是我如何布置应用程序的信息。 希望有一个概念上的答案来建议我应该如何做,而不是仅是代码答案。
服务:
路由器:
angular.module('routerRoutes', ['ngRoute'])
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'homeController',
controllerAs: 'home'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'aboutController',
controllerAs: 'about'
})
.when('/contact', {
templateUrl: 'views/contact.html',
controller: 'contactController',
controllerAs: 'contact'
})
.when('/login', {
templateUrl: 'views/login.html',
controller: 'adminController',
controllerAs: 'login'
})
.when('/admin', {
templateUrl: 'views/admin/admin.html',
controller: 'adminController',
controllerAs: 'admin'
});
$locationProvider.html5Mode(true);
});
控制器:
homeController,aboutController和contactController通常现在为空
adminController:
.controller('adminController',function($ rootScope,$ location,Auth){
var vm = this; vm.loggedIn = Auth.isLoggedIn(); $rootScope.$on('$routeChangeStart', function() { vm.loggedIn = Auth.isLoggedIn(); window.alert(vm.loggedIn); // this gives correct answer and works Auth.getUser() .success(function(data) { vm.user = data; }); }); vm.doLogin = function() { vm.error = ''; Auth.login(vm.loginData.username, vm.loginData.password) .success(function(data) { vm.user = data.username; if (data.success) $location.path('/admin'); else vm.error = data.message; }); }; vm.doLogout = function() { Auth.logout(); vm.user = {}; $location.path('/login'); };
});
最后,下面是我的index.html(仅是正文):
<body class="container" ng-app="meanApp" ng-controller="adminController as admin">
<a href="/"><i class="fa fa-home">Home </i></a>
<a href="/about"><i class="fa fa-shield">About </i></a>
<a href="/contact"><i class="fa fa-comment">Contact</i></a>
<a href="/admin"><i class="fa fa-comment">Admin</i></a>
<ul class="nav navbar-nav navbar-right">
<li ng-if="!admin.loggedIn"><a href="/login">Login</a></li>
<li ng-if="admin.loggedIn" class="navbar-text">Hello {{ admin.user.username }}</li>
<li ng-if="admin.loggedIn"><a href="#" ng-click="admin.doLogout()">Logout</a></li>
</ul>
<main>
<div ng-view>
</div>
</main>
</body>
我将不会粘贴注入的其他html页面,因为它们上还没有任何东西(login.html只有两个输入字段和提交按钮)。
有几个问题:
另一个优点:
我采用了自定义属性路由来保护应用程序中的路由。 侦听并检查每个发生的状态更改是否具有此属性。 如果设置了此属性,则它将检查用户是否已登录;如果未登录,则会将其路由到“登录”状态。
我在实现该功能的当前项目中使用了UI-ROUTER。 我在路由中使用了一个自定义参数“ data”。
在.config块中声明我的开放路线:
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'login/login.html',
controller: 'LoginController',
controllerAs: 'vm'
})
.state('home', {
url: '',
templateUrl: 'layout/shell.html',
controller: 'ShellController',
controllerAs: 'vm',
data: {
requireLogin: true
}
})
然后,将其添加到应用程序中的.run,在其中查找ui路由器的$ stateChangeStart事件并在状态声明中查看我的自定义属性(“数据”):
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
var requireLogin = toState.hasOwnProperty('data') && toState.data.requireLogin;
if (requireLogin && !authService.isLoggedIn()) {
event.preventDefault();
authService.setDestinationState(toState.name);
$state.go('login');
}
if (toState.name !== 'login') {
authService.setDestinationState(toState.name);
}
});
如果您想知道authService.setDestinationState的功能是什么...它将保留用户尝试访问的URL ...一旦成功登录,它将自动将其转发到该状态(请参见下文):
function login() {
authService.authLogin(vm.credentials)
.then(loginComplete)
.catch(loginFailed);
function loginComplete(data, status, headers, config) {
vm.user = data;
$rootScope.$broadcast('authorized');
$state.go(authService.getDestinationState());
}
function loginFailed(status) {
console.log('XHR Failed for login.');
vm.user = undefined;
vm.error = 'Error: Invalid user or password. ' + status.error;
toastr.error(vm.error, {closeButton: true} );
}
}
定义管理路由时,可以定义一个名为resolve的属性。 resolve中的每个属性都是一个函数(可以是可注入函数)。 这个函数应该返回一个promise,promise的结果可以注入到控制器中。
有关解决的更多信息,请参见http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx 。
您可以按以下方式使用resolve进行身份验证检查。
var authenticateRoute = ['$q', '$http' , function ($q, $http) {
var deferred = $q.defer();
$http.get("http://api.domain.com/whoami")
.then(function(response) {
if (response.data.userId) deferred.resolve(response.data.userId);
else window.location.href = "#/Login"
});
return deferred.promise();
}]
// ...
.when('/admin', {
templateUrl: 'views/admin/admin.html',
controller: 'adminController',
controllerAs: 'admin',
resolve: {
authenticatedAs: authenticateRoute
}
});
这样,您可以传递经过身份验证的用户ID(即使为null),也可以让控制器处理它,例如,如果您需要上下文消息。 否则,您可以执行上述操作,并且仅在身份验证请求中有用户ID时才这样做,否则重定向到您的登录路由。
希望这可以帮助! / AJ
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.