AngularJS 认证 + RESTful API [英] AngularJS Authentication + RESTful API

查看:31
本文介绍了AngularJS 认证 + RESTful API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这已经在几个不同的问题和几个不同的教程中进行了讨论,但是我之前遇到的所有资源都没有完全一针见血.

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.

  • 通过 POST 从 http://client.foo 登录到 http://api.foo/login
  • 为提供 logout 路由的用户提供登录"GUI/组件状态
  • 能够在用户注销/注销时更新"用户界面.这是最令人沮丧的
  • 保护我的路由以检查身份验证状态(他们是否需要)并相应地将用户重定向到登录页面
  • Login via POST from http://client.foo to http://api.foo/login
  • Have a "logged in" GUI/component state for the user that provides a logout route
  • 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
  • 每次导航到不同的页面时,我都需要调用 api.foo/status 来确定用户是否已登录.(ATM 我使用 Express 作为路由) 这会导致打嗝,因为 Angular 决定了诸如 ng-show="user.is_authenticated"
  • 之类的事情
  • 当我成功登录/注销时,我需要刷新页面(我不想这样做)以填充诸如 {{user.first_name}} 之类的内容,或者在注销的情况下,清空该值.
  • Every time I navigate to a different page, I need to make the call to api.foo/status to determine whether or not user is logged in. (ATM I'm using Express for routes) This causes a hiccup as Angular determines things like ng-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.
// Sample response from `/status` if successful 

{
   customer: {...},
   is_authenticated: true,
   authentication_timeout: 1376959033,
   ...
}

我的尝试

  • 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 data 而不是 query paramsPOST.文档没有发现任何问题.
  • 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 POST with post data and not query params. The docs turned up nothing on the matter.
      • 似乎每个教程都依赖于一些数据库(大量的 Mongo、Couch、PHP+MySQL、无限)解决方案,并且没有一个纯粹依赖于与 RESTful API 的通信来保持登录状态.登录后,将使用 withCredentials:true 发送额外的 POST/GET,所以这不是问题
      • 我找不到任何没有后端语言的 Angular+REST+Auth 示例/教程/存储库.
      • 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.

      诚然,我是 Angular 的新手,如果我以一种荒谬的方式接近这个,我不会感到惊讶;如果有人提出替代方案,我会很高兴——即使是从汤到坚果.

      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.

      我使用 Express 主要是因为我真的很喜欢 JadeStylus——我不喜欢 Express' 路由,如果我想要做的只有 Angular 的路由才有可能,我会放弃它.

      I'm using Express mostly because I really love Jade and 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.

      预先感谢任何人可以提供的任何帮助.请不要让我谷歌它,因为我有大约 26 页的紫色链接.;-)

      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. ;-)

      1这个解决方案依赖于 Angular 的 $httpBackend mock,并且不清楚如何让它与真实服务器通信.

      1This solution relies on Angular's $httpBackend mock, and it's unclear how to make it talk to a real server.

      2这是最接近的,但由于我有一个需要验证的现有 API,我无法使用护照的localStrategy",而且看起来疯狂编写一个 OAUTH 服务......只有我打算使用.

      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 insane to write an OAUTH service...that only I intended to use.

      推荐答案

      这摘自我关于 url 路由授权和元素安全的博客文章 此处 但我将简要总结要点:-)

      This is taken from my blog post on url route authorisation and element security here but I will briefly summaries the main points :-)

      前端 Web 应用程序的安全性只是阻止 Joe Public 的开始措施,但是任何具有一些 Web 知识的用户都可以绕过它,因此您也应该始终拥有安全服务器端.

      angular 中安全问题的主要问题是路由安全,幸运的是,在 angular 中定义路由时,您将创建一个对象,一个可以具有其他属性的对象.我的方法的基石是向该路由对象添加一个安全对象,该对象基本上定义了用户必须具有的角色才能访问特定路由.

      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.

       // 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();
                      }
                  }
              });
          }]);
      

      这里的关键实际上是.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.

      现在我们可以拦截路由了,我们可以做很多很酷的事情,包括重定向之后登录,如果用户登陆他们需要登录的路线.

      Now we can intercept routes we can do quite a few cool things including redirecting after a login if a user landed on a route that they needed to be logged in for.

      解决方案的第二部分是能够根据权限向用户隐藏/显示 UI 元素.这是通过一个简单的指令实现的.

      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.

      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 post for a much more detailed overview to the approach.

      这篇关于AngularJS 认证 + RESTful API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆