node.js AngularJS 认证 + RESTful API
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18325324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS Authentication + RESTful API
提问by couzzi
Angular+RESTful Client-side Communication w/ API for Auth/(re)Routing
带有用于身份验证/(重新)路由的 API 的 Angular + RESTful 客户端通信
This has been covered in a few different questions, and in a few different tutorials, but all of the previous resources I've encountered don't quite hit the nail on the head.
这已经在几个不同的问题和几个不同的教程中进行了讨论,但是我之前遇到的所有资源都没有完全一针见血。
In a nut-shell, I need to
简而言之,我需要
- Login via POST from
http://client.footohttp://api.foo/login - Have a "logged in" GUI/component state for the user that provides a
logoutroute - Be able to "update" the UI when the user logs out / logs out. This has been the most frustrating
- Secure my routes to check for authenticated-state (should they need it) and redirect the user to the login page accordingly
- 通过 POST 登录从
http://client.foo到http://api.foo/login - 为提供
logout路由的用户提供“登录”GUI/组件状态 - 能够在用户注销/注销时“更新”UI。 这是最令人沮丧的
- 保护我的路由以检查身份验证状态(他们是否需要)并相应地将用户重定向到登录页面
My issues are
我的问题是
- Every time I navigate to a different page, I need to make the call to
api.foo/statusto determine whether or not user is logged in. (ATM I'm using Express for routes) This causes a hiccup as Angular determines things likeng-show="user.is_authenticated" - When I successfully login/logout, I need to refresh the page (I don't want to have to do this) in order to populate things like
{{user.first_name}}, or in the case of logging out, empty that value out.
- 每次导航到不同的页面时,我都需要调用以
api.foo/status确定用户是否登录。(ATM 我使用 Express 作为路由)这会导致打嗝,因为 Angular 确定诸如ng-show="user.is_authenticated" - 当我成功登录/注销时,我需要刷新页面(我不想这样做)以填充诸如 之类的内容
{{user.first_name}},或者在注销的情况下,清空该值。
// Sample response from `/status` if successful
{
customer: {...},
is_authenticated: true,
authentication_timeout: 1376959033,
...
}
What I've tried
我试过的
- http://witoldsz.github.io/angular-http-auth/1
- http://www.frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/2
- https://github.com/mgonto/restangular(For the life of me I could not figure out how to
POSTwithpost dataand notquery params. The docs turned up nothing on the matter.
- http://witoldsz.github.io/angular-http-auth/ 1
- http://www.frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/ 2
- https://github.com/mgonto/restangular(对于我的生活,我不知道如何
POST使用post data和不使用query params。文档没有发现任何关于此事的信息。
Why I feel like I'm losing my mind
为什么我觉得我正在失去理智
- It seems as though every tutorial relies on some database (lots of Mongo, Couch, PHP+MySQL, ad infinitum) solution, and none rely purely on communication with a RESTful API to persist logged-in states. Once logged in, additional POSTs/GETs are sent with
withCredentials:true, so that's not the issue - I cannot find ANY examples/tutorials/repos that do Angular+REST+Auth, sans a backend language.
- 似乎每个教程都依赖于一些数据库(很多 Mongo、Couch、PHP+MySQL、无限)解决方案,并且没有一个纯粹依赖于与 RESTful API 的通信来保持登录状态。登录后,将使用 发送额外的 POST/GET
withCredentials:true,所以这不是问题 - 我找不到任何做 Angular+REST+Auth 的示例/教程/存储库,没有后端语言。
I'm not too proud
我不太骄傲
Admittedly, I'm new to Angular, and would not be surprised if I'm approaching this in a ridiculous way; I'd be thrilled if someone suggest an alternative—even if it's soup-to-nuts.
诚然,我是 Angular 的新手,如果我以一种荒谬的方式接近这个,我不会感到惊讶;如果有人提出替代方案,我会很高兴——即使是从汤到坚果。
I'm using Expressmostly because I really love Jadeand Stylus— I'm not married to the Express' routing and will give it up if what I want to do is only possible with Angular's routing.
我使用它Express主要是因为我真的很喜欢Jade并且Stylus- 我没有嫁给Express' 路由,如果我想做的事情只能使用 Angular 的路由,我会放弃它。
Thanks in advance for any help anyone can provide. And please don't ask me to Google it, because I have about 26 pages of purple links. ;-)
预先感谢任何人可以提供的任何帮助。请不要让我谷歌它,因为我有大约 26 页的紫色链接。;-)
1This solution relies on Angular's $httpBackend mock, and it's unclear how to make it talk to a real server.
1此解决方案依赖于 Angular 的 $httpBackend 模拟,目前尚不清楚如何使其与真实服务器通信。
2This was the closest, but since I have an existing API I need to authenticate with, I could not use passport's 'localStrategy', and it seemed insaneto write an OAUTH service...that only I intended to use.
2这是最接近的,但由于我有一个需要验证的现有 API,我无法使用护照的“localStrategy”,编写 OAUTH 服务似乎很疯狂……只有我打算使用。
采纳答案by Jon
This is taken from my blog post on url route authorisation and element security herebut I will briefly summaries the main points :-)
这是从我的博客文章对URL路径的授权和安全因素考虑在这里,但我将简要总结要点:-)
Security in frontend web application is merely a starting measure to stop Joe Public, however any user with some web knowledge can circumvent it so you should always have security server-side as well.
前端 Web 应用程序的安全性只是阻止 Joe Public 的一个开始措施,但是任何具有一些 Web 知识的用户都可以绕过它,因此您也应该始终拥有安全服务器端。
The main concern around security stuff in angular is route security, luckily when defining a route in angular you are create an object, an object that can have other properties. The cornerstone to my approach is to add a security object to this route object which basically defines the roles the user must be in to be able to access a particular route.
angular 中安全性的主要问题是路由安全性,幸运的是,在 angular 中定义路由时,您正在创建一个对象,一个可以具有其他属性的对象。我的方法的基石是向这个路由对象添加一个安全对象,它基本上定义了用户必须处于的角色才能访问特定的路由。
// route which requires the user to be logged in and have the 'Admin' or 'UserManager' permission
$routeProvider.when('/admin/users', {
controller: 'userListCtrl',
templateUrl: 'js/modules/admin/html/users.tmpl.html',
access: {
requiresLogin: true,
requiredPermissions: ['Admin', 'UserManager'],
permissionType: 'AtLeastOne'
});
The whole approach focuses around an authorisation service which basically does the check to see if the user has the required permissions. This service abstract the concerns away from the other parts of this solution to do with the user and their actual permission that would have been retrieved from the server during login. While the code is quite verbose it is fully explained in my blog post. However, it basically handle the permission check and two modes of authorisation. The first is that the user must have at least on of the defined permissions, the second is the user must have all of the defined permissions.
整个方法侧重于授权服务,该服务基本上会检查用户是否具有所需的权限。该服务将关注点从该解决方案的其他部分中抽象出来,这些部分与用户及其在登录期间从服务器检索的实际权限有关。虽然代码非常冗长,但在我的博客文章中已对其进行了充分解释。但是,它基本上处理权限检查和两种授权模式。第一个是用户必须至少拥有一个定义的权限,第二个是用户必须拥有所有定义的权限。
angular.module(jcs.modules.auth.name).factory(jcs.modules.auth.services.authorization, [
'authentication',
function (authentication) {
var authorize = function (loginRequired, requiredPermissions, permissionCheckType) {
var result = jcs.modules.auth.enums.authorised.authorised,
user = authentication.getCurrentLoginUser(),
loweredPermissions = [],
hasPermission = true,
permission, i;
permissionCheckType = permissionCheckType || jcs.modules.auth.enums.permissionCheckType.atLeastOne;
if (loginRequired === true && user === undefined) {
result = jcs.modules.auth.enums.authorised.loginRequired;
} else if ((loginRequired === true && user !== undefined) &&
(requiredPermissions === undefined || requiredPermissions.length === 0)) {
// Login is required but no specific permissions are specified.
result = jcs.modules.auth.enums.authorised.authorised;
} else if (requiredPermissions) {
loweredPermissions = [];
angular.forEach(user.permissions, function (permission) {
loweredPermissions.push(permission.toLowerCase());
});
for (i = 0; i < requiredPermissions.length; i += 1) {
permission = requiredPermissions[i].toLowerCase();
if (permissionCheckType === jcs.modules.auth.enums.permissionCheckType.combinationRequired) {
hasPermission = hasPermission && loweredPermissions.indexOf(permission) > -1;
// if all the permissions are required and hasPermission is false there is no point carrying on
if (hasPermission === false) {
break;
}
} else if (permissionCheckType === jcs.modules.auth.enums.permissionCheckType.atLeastOne) {
hasPermission = loweredPermissions.indexOf(permission) > -1;
// if we only need one of the permissions and we have it there is no point carrying on
if (hasPermission) {
break;
}
}
}
result = hasPermission ?
jcs.modules.auth.enums.authorised.authorised :
jcs.modules.auth.enums.authorised.notAuthorised;
}
return result;
};
Now that a route has security you need a way of determining if a user can access the route when a route change has been started. To do this we be intercepting the route change request, examining the route object (with our new access object on it) and if the user cannot access the view we replace the route with another one.
既然路由具有安全性,您需要一种方法来确定用户是否可以在路由更改开始时访问该路由。为此,我们拦截路由更改请求,检查路由对象(带有我们的新访问对象),如果用户无法访问视图,我们将用另一个路由替换。
angular.module(jcs.modules.auth.name).run([
'$rootScope',
'$location',
jcs.modules.auth.services.authorization,
function ($rootScope, $location, authorization) {
$rootScope.$on('$routeChangeStart', function (event, next) {
var authorised;
if (next.access !== undefined) {
authorised = authorization.authorize(next.access.loginRequired,
next.access.permissions,
next.access.permissionCheckType);
if (authorised === jcs.modules.auth.enums.authorised.loginRequired) {
$location.path(jcs.modules.auth.routes.login);
} else if (authorised === jcs.modules.auth.enums.authorised.notAuthorised) {
$location.path(jcs.modules.auth.routes.notAuthorised).replace();
}
}
});
}]);
The key here really is the '.replace()' as this replace the current route (the one they have not got rights to see) with the route we are redirecting them to. This stop any then navigating back to the unauthorised route.
这里的关键确实是“.replace()”,因为它用我们将他们重定向到的路由替换了当前路由(他们无权查看的路由)。这将停止任何然后导航回未经授权的路线。
Now we can intercept routes we can do quite a few cool things including redirecting after a loginif a user landed on a route that they needed to be logged in for.
现在我们可以拦截路由,我们可以做很多很酷的事情,包括登录后重定向,如果用户登陆他们需要登录的路由。
The second part of the solution is being able to hide/show UI element to the user depending on there rights. This is achieve via a simple directive.
解决方案的第二部分是能够根据权限向用户隐藏/显示 UI 元素。这是通过一个简单的指令实现的。
angular.module(jcs.modules.auth.name).directive('access', [
jcs.modules.auth.services.authorization,
function (authorization) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var makeVisible = function () {
element.removeClass('hidden');
},
makeHidden = function () {
element.addClass('hidden');
},
determineVisibility = function (resetFirst) {
var result;
if (resetFirst) {
makeVisible();
}
result = authorization.authorize(true, roles, attrs.accessPermissionType);
if (result === jcs.modules.auth.enums.authorised.authorised) {
makeVisible();
} else {
makeHidden();
}
},
roles = attrs.access.split(',');
if (roles.length > 0) {
determineVisibility(true);
}
}
};
}]);
You would then sure an element like so:
然后你会确定一个像这样的元素:
<button type="button" access="CanEditUser, Admin" access-permission-type="AtLeastOne">Save User</button>
Read my full blog postfor a much more detailed overview to the approach.
阅读我的完整博客文章,了解该方法的更详细概述。
回答by Timothy E. Johansson
I've written an AngularJS modulefor UserAppthat does pretty much everything you ask for. You could either:
我为UserApp编写了一个AngularJS 模块,它几乎可以满足您的所有要求。你可以:
- Modify the module and attach the functions to your own API, or
- Use the module together with the user management API, UserApp
- 修改模块并将函数附加到您自己的 API,或
- 模块与用户管理 API UserApp一起使用
https://github.com/userapp-io/userapp-angular
https://github.com/userapp-io/userapp-angular
It supports protected/public routes, rerouting on login/logout, heartbeats for status checks, stores the session token in a cookie, events, etc.
它支持受保护/公共路由、登录/注销时重新路由、状态检查的心跳、将会话令牌存储在 cookie、事件等中。
If you want to give UserApp a try, take the course on Codecademy.
如果您想尝试使用 UserApp,请参加Codecademy 课程。
Here's some examples of how it works:
以下是它如何工作的一些示例:
Login form with error handling:
<form ua-login ua-error="error-msg"> <input name="login" placeholder="Username"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Log in</button> <p id="error-msg"></p> </form>Signup form with error handling:
<form ua-signup ua-error="error-msg"> <input name="first_name" placeholder="Your name"><br> <input name="login" ua-is-email placeholder="Email"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Create account</button> <p id="error-msg"></p> </form>How to specify which routes that should be public, and which route that is the login form:
$routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true}); $routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});The
.otherwise()route should be set to where you want your users to be redirected after login. Example:$routeProvider.otherwise({redirectTo: '/home'});Log out link:
<a href="#" ua-logout>Log Out</a>(Ends the session and redirects to the login route)
Access user properties:
User info is accessed using the
userservice, e.g:user.current.emailOr in the template:
<span>{{ user.email }}</span>Hide elements that should only be visible when logged in:
<div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>Show an element based on permissions:
<div ua-has-permission="admin">You are an admin</div>
带有错误处理的登录表单:
<form ua-login ua-error="error-msg"> <input name="login" placeholder="Username"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Log in</button> <p id="error-msg"></p> </form>带有错误处理的注册表单:
<form ua-signup ua-error="error-msg"> <input name="first_name" placeholder="Your name"><br> <input name="login" ua-is-email placeholder="Email"><br> <input name="password" placeholder="Password" type="password"><br> <button type="submit">Create account</button> <p id="error-msg"></p> </form>如何指定哪些路由应该是公开的,哪些路由是登录表单:
$routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true}); $routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});该
.otherwise()路由应设置为您希望用户在登录后重定向到的位置。例子:$routeProvider.otherwise({redirectTo: '/home'});登出链接:
<a href="#" ua-logout>Log Out</a>(结束会话并重定向到登录路由)
访问用户属性:
使用该
user服务访问用户信息,例如:user.current.email或者在模板中:
<span>{{ user.email }}</span>隐藏只应在登录时可见的元素:
<div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>根据权限显示元素:
<div ua-has-permission="admin">You are an admin</div>
And to authenticate to your back-end services, just use user.token()to get the session token and send it with the AJAX request. At the back-end, use the UserApp API(if you use UserApp) to check if the token is valid or not.
并且要对您的后端服务进行身份验证,只需使用user.token()获取会话令牌并将其与 AJAX 请求一起发送。在后端,使用UserApp API(如果您使用 UserApp)来检查令牌是否有效。
If you need any help, just let me know :)
如果您需要任何帮助,请告诉我:)
回答by Alex Arvanitidis
I've created a github repo summing up this article basically: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
我已经创建了一个 github repo 基本上总结了这篇文章:https: //medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
I'll try to explain as good as possible, hope I help some of you out there:
我会尽量解释清楚,希望能帮到你们:
(1) app.js:Creation of authentication constants on app definition
(1) app.js:在应用定义上创建认证常量
var loginApp = angular.module('loginApp', ['ui.router', 'ui.bootstrap'])
/*Constants regarding user login defined here*/
.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:All following functions are implemented in auth.js service. The $http service is used to communicate with the server for the authentication procedures. Also contains functions on authorization, that is if the user is allowed to perform a certain action.
(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:A singleton to keep user data. The implementation here depends on you.
(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) Parent controller:Consider this as the "main" function of your application, all controllers inherit from this controller, and it's the backbone of the authentication of this app.
(4) 父控制器:把它当作你的应用程序的“主要”功能,所有控制器都继承自这个控制器,它是这个应用程序认证的支柱。
<body ng-controller="ParentController">
[...]
</body>
(5) Access control:To deny access on certain routes 2 steps have to be implemented:
(5) 访问控制:要拒绝某些路由的访问,必须执行 2 个步骤:
a) Add data of the roles allowed to access each route, on ui router's $stateProvider service as can be seen below (same can work for ngRoute).
a) 在 ui 路由器的 $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) On $rootScope.$on('$stateChangeStart') add the function to prevent state change if the user is not authorized.
b) 在 $rootScope.$on('$stateChangeStart') 上添加函数以防止用户未经授权时状态更改。
$rootScope.$on('$stateChangeStart', function (event, next) {
var authorizedRoles = next.data.authorizedRoles;
if (!Auth.isAuthorized(authorizedRoles)) {
event.preventDefault();
if (Auth.isAuthenticated()) {
// user is not allowed
$rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
} else {d
// user is not logged in
$rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
}
}
});
(6) Auth interceptor:This is implemented, but can't be checked on the scope of this code. After each $http request, this interceptor checks the status code, if one of the below is returned, then it broadcasts an event to force the user to log-in again.
(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);
}
};
} ]);
P.S.A bug with the form data autofill as stated on the 1st article can be easily avoided by adding the directive that is included in directives.js.
PS通过添加包含在directives.js 中的指令,可以轻松避免第一篇文章中所述的表单数据自动填充错误。
P.S.2This code can be easily tweaked by the user, to allow different routes to be seen, or display content that was not meant to be displayed. The logic MUST be implemented server-side, this is just a way to show things properly on your ng-app.
PS2用户可以轻松调整此代码,以允许查看不同的路线,或显示不打算显示的内容。逻辑必须在服务器端实现,这只是在 ng-app 上正确显示内容的一种方式。
回答by shaunhusain
I haven't been using $resource because I'm just hand crafting my service calls for my application. That said I've handled login by having a service which depends on all the other services that get some sort of initialization data. When the login succeeds it triggers for initialization of all the services.
我没有使用 $resource 因为我只是为我的应用程序手工制作服务调用。也就是说,我通过拥有一个服务来处理登录,该服务依赖于获取某种初始化数据的所有其他服务。当登录成功时,它会触发所有服务的初始化。
Within my controller scope I watch the loginServiceInformation and populate some properties of the model accordingly (to trigger the appropriate ng-show/hide). With regard to routing I'm using Angular's built in routing and I simply have an ng-hide based on the loggedIn boolean shown here, it shows text to request login or else the div with the ng-view attribute (so if not logged in immediately after login you're on the correct page, currently I load data for all views but I believe this could be more selective if necessary)
在我的控制器范围内,我观察 loginServiceInformation 并相应地填充模型的一些属性(以触发适当的 ng-show/hide)。关于路由,我使用的是 Angular 的内置路由,我只是有一个基于这里显示的 loginIn 布尔值的 ng-hide,它显示请求登录的文本或具有 ng-view 属性的 div(所以如果没有登录登录后立即进入正确的页面,目前我加载所有视图的数据,但我相信如果有必要,这可能更具选择性)
//Services
angular.module("loginModule.services", ["gardenModule.services",
"surveyModule.services",
"userModule.services",
"cropModule.services"
]).service(
'loginService',
[ "$http",
"$q",
"gardenService",
"surveyService",
"userService",
"cropService",
function ( $http,
$q,
gardenService,
surveyService,
userService,
cropService) {
var service = {
loginInformation: {loggedIn:false, username: undefined, loginAttemptFailed:false, loggedInUser: {}, loadingData:false},
getLoggedInUser:function(username, password)
{
service.loginInformation.loadingData = true;
var deferred = $q.defer();
$http.get("php/login/getLoggedInUser.php").success(function(data){
service.loginInformation.loggedIn = true;
service.loginInformation.loginAttemptFailed = false;
service.loginInformation.loggedInUser = data;
gardenService.initialize();
surveyService.initialize();
userService.initialize();
cropService.initialize();
service.loginInformation.loadingData = false;
deferred.resolve(data);
}).error(function(error) {
service.loginInformation.loggedIn = false;
deferred.reject(error);
});
return deferred.promise;
},
login:function(username, password)
{
var deferred = $q.defer();
$http.post("php/login/login.php", {username:username, password:password}).success(function(data){
service.loginInformation.loggedInUser = data;
service.loginInformation.loggedIn = true;
service.loginInformation.loginAttemptFailed = false;
gardenService.initialize();
surveyService.initialize();
userService.initialize();
cropService.initialize();
deferred.resolve(data);
}).error(function(error) {
service.loginInformation.loggedInUser = {};
service.loginInformation.loggedIn = false;
service.loginInformation.loginAttemptFailed = true;
deferred.reject(error);
});
return deferred.promise;
},
logout:function()
{
var deferred = $q.defer();
$http.post("php/login/logout.php").then(function(data){
service.loginInformation.loggedInUser = {};
service.loginInformation.loggedIn = false;
deferred.resolve(data);
}, function(error) {
service.loginInformation.loggedInUser = {};
service.loginInformation.loggedIn = false;
deferred.reject(error);
});
return deferred.promise;
}
};
service.getLoggedInUser();
return service;
}]);
//Controllers
angular.module("loginModule.controllers", ['loginModule.services']).controller("LoginCtrl", ["$scope", "$location", "loginService", function($scope, $location, loginService){
$scope.loginModel = {
loadingData:true,
inputUsername: undefined,
inputPassword: undefined,
curLoginUrl:"partials/login/default.html",
loginFailed:false,
loginServiceInformation:{}
};
$scope.login = function(username, password) {
loginService.login(username,password).then(function(data){
$scope.loginModel.curLoginUrl = "partials/login/logoutButton.html";
});
}
$scope.logout = function(username, password) {
loginService.logout().then(function(data){
$scope.loginModel.curLoginUrl = "partials/login/default.html";
$scope.loginModel.inputPassword = undefined;
$scope.loginModel.inputUsername = undefined;
$location.path("home");
});
}
$scope.switchUser = function(username, password) {
loginService.logout().then(function(data){
$scope.loginModel.curLoginUrl = "partials/login/loginForm.html";
$scope.loginModel.inputPassword = undefined;
$scope.loginModel.inputUsername = undefined;
});
}
$scope.showLoginForm = function() {
$scope.loginModel.curLoginUrl = "partials/login/loginForm.html";
}
$scope.hideLoginForm = function() {
$scope.loginModel.curLoginUrl = "partials/login/default.html";
}
$scope.$watch(function(){return loginService.loginInformation}, function(newVal) {
$scope.loginModel.loginServiceInformation = newVal;
if(newVal.loggedIn)
{
$scope.loginModel.curLoginUrl = "partials/login/logoutButton.html";
}
}, true);
}]);
angular.module("loginModule", ["loginModule.services", "loginModule.controllers"]);
The HTML
HTML
<div style="height:40px;z-index:200;position:relative">
<div class="well">
<form
ng-submit="login(loginModel.inputUsername, loginModel.inputPassword)">
<input
type="text"
ng-model="loginModel.inputUsername"
placeholder="Username"/><br/>
<input
type="password"
ng-model="loginModel.inputPassword"
placeholder="Password"/><br/>
<button
class="btn btn-primary">Submit</button>
<button
class="btn"
ng-click="hideLoginForm()">Cancel</button>
</form>
<div
ng-show="loginModel.loginServiceInformation.loginAttemptFailed">
Login attempt failed
</div>
</div>
</div>
The Base HTML that uses the parts above to complete the picture:
使用上述部分完成图片的基础 HTML:
<body ng-controller="NavigationCtrl" ng-init="initialize()">
<div id="outerContainer" ng-controller="LoginCtrl">
<div style="height:20px"></div>
<ng-include src="'partials/header.html'"></ng-include>
<div id="contentRegion">
<div ng-hide="loginModel.loginServiceInformation.loggedIn">Please login to continue.
<br/><br/>
This new version of this site is currently under construction.
<br/><br/>
If you need the legacy site and database <a href="legacy/">click here.</a></div>
<div ng-view ng-show="loginModel.loginServiceInformation.loggedIn"></div>
</div>
<div class="clear"></div>
<ng-include src="'partials/footer.html'"></ng-include>
</div>
</body>
I have the login controller defined with an ng-controller higher up in the DOM so that I can change the body area of my page based on the loggedIn variable.
我在 DOM 中用 ng-controller 定义了登录控制器,以便我可以根据 loginIn 变量更改页面的正文区域。
Note I haven't implemented form validation here yet. Also admittedly still quite fresh to Angular so any pointers to things in this post are welcome. Although this doesn't answer the question directly since it isn't a RESTful based implementation I believe the same can be adapted to $resources since it's built on top of $http calls.
注意我还没有在这里实现表单验证。诚然,Angular 仍然很新鲜,因此欢迎对本文中的内容提出任何建议。虽然这不能直接回答问题,因为它不是基于 RESTful 的实现,但我相信同样可以适用于 $resources,因为它构建在 $http 调用之上。

