我已经创建了一个Github仓库,总结了这篇文章的基本内容:
https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
ng-login Github 仓库
Plunker
我尽可能地解释清楚,希望能帮助你们中的一些人:
(1) app.js: 在应用程序定义中创建身份验证常量。
var loginApp = angular.module('loginApp', ['ui.router', 'ui.bootstrap'])
.constant('USER_ROLES', {
all : '*',
admin : 'admin',
editor : 'editor',
guest : 'guest'
}).constant('AUTH_EVENTS', {
loginSuccess : 'auth-login-success',
loginFailed : 'auth-login-failed',
logoutSuccess : 'auth-logout-success',
sessionTimeout : 'auth-session-timeout',
notAuthenticated : 'auth-not-authenticated',
notAuthorized : 'auth-not-authorized'
})
(2) Auth Service: 所有下列函数均在 auth.js 服务中实现。使用 $http 服务与服务器通信进行身份验证流程。还包含授权功能,即确定用户是否可以执行某个操作。
angular.module('loginApp')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS',
function($http, $rootScope, $window, Session, AUTH_EVENTS) {
authService.login() = [...]
authService.isAuthenticated() = [...]
authService.isAuthorized() = [...]
authService.logout() = [...]
return authService;
} ]);
(3) 会话(Session): 用于保存用户数据的单例对象。其实现取决于您。
angular.module('loginApp').service('Session', function($rootScope, USER_ROLES) {
this.create = function(user) {
this.user = user;
this.userRole = user.userRole;
};
this.destroy = function() {
this.user = null;
this.userRole = null;
};
return this;
});
(4) 父级控制器: 将其视为应用程序的“主”功能,所有控制器都继承自此控制器,它是此应用程序身份验证的支柱。
<body ng-controller="ParentController">
[...]
</body>
(5) 访问控制:要拒绝某些路由的访问,需要执行两个步骤:
a)向ui router的$stateProvider服务中添加允许访问每个路由的角色数据,如下所示(ngRoute也可以适用)。
.config(function ($stateProvider, USER_ROLES) {
$stateProvider.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard/index.html',
data: {
authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
}
});
})
b) 在 $rootScope.$on('$stateChangeStart') 中添加函数,以防止未经授权的用户改变状态。
$rootScope.$on('$stateChangeStart', function (event, next) {
var authorizedRoles = next.data.authorizedRoles;
if (!Auth.isAuthorized(authorizedRoles)) {
event.preventDefault();
if (Auth.isAuthenticated()) {
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
} else {d
$rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
}
}
});
(6) Auth拦截器:这个已经实现了,但是无法在此代码范围内进行检查。每次$http请求后,该拦截器会检查状态码,如果返回以下任何一个,则广播一个事件强制用户再次登录。
angular.module('loginApp')
.factory('AuthInterceptor', [ '$rootScope', '$q', 'Session', 'AUTH_EVENTS',
function($rootScope, $q, Session, AUTH_EVENTS) {
return {
responseError : function(response) {
$rootScope.$broadcast({
401 : AUTH_EVENTS.notAuthenticated,
403 : AUTH_EVENTS.notAuthorized,
419 : AUTH_EVENTS.sessionTimeout,
440 : AUTH_EVENTS.sessionTimeout
}[response.status], response);
return $q.reject(response);
}
};
} ]);
附言:如第一篇文章所述,表单数据自动填充的错误可以通过在directives.js中添加指令来轻松避免。
附言2:用户可以轻松地调整此代码,以允许查看不同的路由,或显示不应显示的内容。逻辑必须在服务器端实现,这只是一种在ng-app上正确显示内容的方法。
$cookie
或$cookieStore
。服务器创建的cookie会被返回并存储在浏览器中,当我进行其他需要身份验证的REST调用时,我在我的调用中设置withCredentials:true
。这很好用,它可以维护已登录状态,并保护/隐藏路由,直到该用户登录为止,但我遇到了一些问题。 - couzzi