Javascript 如何在已有RESTAPI后端的Angular应用程序中实现登录系统
我和我的朋友正在开发一个应用程序——我的朋友在后端(Node.js),我在前端 他实现了自己的会话,并为我提供了登录时需要调用的Javascript 如何在已有RESTAPI后端的Angular应用程序中实现登录系统,javascript,angularjs,node.js,cookies,login,Javascript,Angularjs,Node.js,Cookies,Login,我和我的朋友正在开发一个应用程序——我的朋友在后端(Node.js),我在前端 他实现了自己的会话,并为我提供了登录时需要调用的URL。例如,一个POST请求 http://ourapp.heroku.com/login 传递用户名和密码 在我这边,在Angular应用程序中,我创建了一个登录页面,当单击login时,该页面将调用Angular服务。如果此服务从服务器接收到200,它会: $cookieStore.put(cookieNames.LOGGED_IN_COOKIE, true);
URL
。例如,一个POST
请求
http://ourapp.heroku.com/login
传递用户名
和密码
在我这边,在Angular应用程序中,我创建了一个登录页面,当单击login
时,该页面将调用Angular服务。如果此服务从服务器接收到200
,它会:
$cookieStore.put(cookieNames.LOGGED_IN_COOKIE, true);
$state.go('home', {}, {reload: true});
问题是,前端的应用程序出现了奇怪的问题。例如,登录和注销通常不起作用。此外,用户即使在注销后也可以进入页面。我发现(至少我认为)我没有正确存储从服务器收到的Cookie,我只是存储了我自己的Cookie
这整件事对我来说仍然很奇怪,因为在PHP或Python应用程序中,你会收到客户端的页面请求,并在发送他请求的页面之前验证他是否登录。在Angular中是不同的-用户已经拥有了所有页面。那么,我如何限制他在不登录的情况下看到的内容,以及如何正确跟踪服务器的cookie?如果使用ui路由器,您可以执行类似的操作: 首先介绍一些对你所在州的访问级别
$stateProvider
.state('admin', {
url: "/admin",
templateUrl: "/app/views/admin.html",
controller: "AdminController",
data: {
accessLevel: 'admin'
}
})
如果您的登录用户具有所需的访问级别,则必须检查状态更改:
您可以创建一个auth服务,该服务实现您的逻辑来登录用户,例如您可以使用该服务
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;
}]);
以及常数:
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 = [];
}
};
}]);
此拦截器还向所有请求(如果可用)添加会话令牌
要使用此拦截器,必须将以下两行添加到app.config():
您应该查找路由更改事件,以查看用户是否需要登录下一页。。。看起来您正在使用ui路由器进行路由,所以将自定义数据添加到状态定义中,如requiresLogin:true,并在事件块(stateChangeStart)中检查它们。哇,很酷的详细答案!谢谢我将实施我的下一个项目。希望能成功,谢谢。既然我在我的项目中使用了这个,它应该可以工作。(可能我遗漏了太多,因为我在项目中实现了一些附加功能)。请记住,您还应该使用相同/类似的访问权限来保护后端。
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 = [];
}
};
}]);
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);
}
}
}]);
$httpProvider.defaults.withCredentials = true;
$httpProvider.interceptors.push("AuthInterceptor");