如何在已经存在的REST API后端的Angular应用程序中实现login系统

我的朋友和我正在build立一个应用程序 – 我的朋友是在后端(Node.js),我在前面。

他在他的最后实现了会话,并为我提供了我需要调用的URL来login。例如,一个POST请求

 http://ourapp.heroku.com/login 

用哪个usernamepassword通过

在我这边,在Angular应用程序中,我创build了一个login页面,当单击Login时,它会调用一个Angular服务。 如果这个服务从服务器收到200 ,它会:

 $cookieStore.put(cookieNames.LOGGED_IN_COOKIE, true); $state.go('home', {}, {reload: true}); 

问题是我们在前端的应用程序有奇怪的问题。 例如,login和登出通常不起作用。 而且,即使在注销之后,用户也能够访问页面。 我想(至less我觉得),我没有正确地存储从服务器接收到的Cookie,我只是存储我自己的。

整个Angular对我来说还是很奇怪的,因为在PHP或者Python应用程序中,你从客户端获得一个页面请求,并且在发送他请求的页面之前validation他是否已经login。 在Angular中是不同的 – 用户已经拥有了所有的页面。 那么,如何在不login的情况下限制他可以看到的内容以及如何正确跟踪服务器的cookie呢?

如果你使用ui-router,你可以做类似这样的事情:

首先向你的国家介绍一些访问级别

 $stateProvider .state('admin', { url: "/admin", templateUrl: "/app/views/admin.html", controller: "AdminController", data: { accessLevel: 'admin' } }) 

那么如果您的login用户具有所需的访问级别,则必须检查状态更改:

你可以创build一个auth服务来实现你的逻辑来login你的用户,例如你可以使用这个服务

 angular.module('app') .factory("AuthService", ["$rootScope", "$http", "AuthSession", "AuthHttpBuffer", "AUTH_EVENTS", function ($rootScope, $http, AuthSession, AuthHttpBuffer, AUTH_EVENTS) { function loginFailed() { $rootScope.$broadcast("auth-change", AUTH_EVENTS.loginFailed); }; AuthSession.load(); $rootScope.$on('$stateChangeStart', function (event, nextState) { if (nextState.data && nextState.data.accessLevel && !service.isAuthorized(nextState.data.accessLevel)) { event.preventDefault(); $rootScope.$broadcast('auth-change', AUTH_EVENTS.loginRequired, nextState.name); } }); var service = { login: function (credentials) { return $http .post('/api/account/login', credentials) .success(function (data, status) { if ((status < 200 || status >= 300) && data.length >= 1) { loginFailed(); return; } AuthSession.create(data.AccessToken, data.User); $rootScope.$broadcast("auth-change", AUTH_EVENTS.loginSuccess); AuthHttpBuffer.retryAll(); }).error(function (data, status) { loginFailed(); }); }, cancel: function () { AuthHttpBuffer.rejectAll(); }, logout: function () { AuthSession.destroy(); $rootScope.$broadcast("auth-change", AUTH_EVENTS.logoutSuccess); }, isAuthenticated: function () { return (AuthSession.token !== null); }, isAuthorized: function (accessLevel) { if (!accessLevel) return true; return (this.isAuthenticated() && AuthSession.user.UserRoles.indexOf(accessLevel) !== -1); } } return service; }]); 

和你的AuthSession服务:

 angular.module('app') .factory("AuthSession", ["$rootScope", "$window", "AUTH_EVENTS", function ($rootScope, $window, AUTH_EVENTS) { var sessionService = { user: null, token: null, //load the stored session data load: function () { var user = ...yourdata... //TODO implement load user data; var token = ...yourdata... //implement load user data; if (!user || !token) return; if (!this.checkTokenExpiration(token)) return; this.user = user; this.token = token; $rootScope.$broadcast("auth-change", AUTH_EVENTS.loginSuccess); }, //save the current data to the session storage save: function () { //TODO save your userdata/token etc. }, //create the current user with the assosiated token create: function (token, user) { this.token = token; this.user = user; if (!angular.isArray(this.user.UserRoles)) this.user.UserRoles = [this.user.UserRoles]; this.save(); }, //destroy an user with all assosiated data destroy: function () { this.token = null; this.user = null; //TODO clear your saved data here }, //check if the supplied access token data is expired checkTokenExpiration: function (token) { if (token === undefined || token === null) return false; var retval = (new Date(token.TokenExpires).getTime() > new Date().getTime()); if (retval === false) { sessionService.destroy(); $rootScope.$broadcast("auth-change", AUTH_EVENTS.sessionTimeout); } return retval; } } return sessionService; }]); 

和常数:

 angular.module('app') .constant('AUTH_EVENTS', { loginSuccess: 'auth-login-success', loginFailed: 'auth-login-failed', logoutSuccess: 'auth-logout-success', loginRequired: 'auth-login-required', sessionTimeout: 'auth-session-timeout', notAuthorized: 'auth-not-authorized' }); 

如果您希望能够抓取url,但您没有正确的访问权限,则可以将请求发送到http缓冲区:

 angular.module('app') .factory('AuthHttpBuffer', ["$injector", function ($injector) { /** Holds all the requests, so they can be re-requested in future. */ var buffer = []; /** Service initialized later because of circular dependency problem. */ var $http; function retryHttpRequest(config, deferred) { function successCallback(response) { deferred.resolve(response); } function errorCallback(response) { deferred.reject(response); } $http = $http || $injector.get('$http'); $http(config).then(successCallback, errorCallback); } return { /** * Appends HTTP request configuration object with deferred response attached to buffer. */ append: function (config, deferred) { buffer.push({ config: config, deferred: deferred }); }, /** * Abandon or reject (if reason provided) all the buffered requests. */ rejectAll: function (reason) { if (reason) { for (var i = 0; i < buffer.length; ++i) { buffer[i].deferred.reject(reason); } } buffer = []; }, /** * Retries all the buffered requests clears the buffer. */ retryAll: function () { for (var i = 0; i < buffer.length; ++i) { retryHttpRequest(buffer[i].config, buffer[i].deferred); } buffer = []; } }; }]); 

如果你还不够,你也可以添加一个拦截器,如果服务器的响应是未经授权的,就会触发auth更改事件:

  angular.module('app') .factory('AuthInterceptor', ["$rootScope", "$q", "AuthSession", "AuthHttpBuffer", "AUTH_EVENTS", function ($rootScope, $q, AuthSession, AuthHttpBuffer, AUTH_EVENTS) { return { request: function (config) { config.headers = config.headers || {}; if (AuthSession.token) { config.headers.Authorization = 'Bearer ' + AuthSession.token.TokenKey; } return config; }, responseError: function (rejection) { if (rejection.status === 401) { var deferred = $q.defer(); AuthHttpBuffer.append(rejection.config, deferred); if (AuthSession.token) { $rootScope.$broadcast('auth-change', AUTH_EVENTS.notAuthorized); } else { $rootScope.$broadcast('auth-change', AUTH_EVENTS.loginRequired); } return deferred.promise; } return $q.reject(rejection); } } }]); 

这个拦截器还会为所有请求添加一个会话令牌(如果有的话)。

要使用这个拦截器,你必须添加以下两行到你的app.config():

  $httpProvider.defaults.withCredentials = true; $httpProvider.interceptors.push("AuthInterceptor");