一尘不染

AngularJS身份验证+ RESTful API

angularjs

带API的Auth +(重新)路由的Angular + RESTful客户端通信

几个不同的问题和一些不同的教程中都涉及到了这一点,但是我所遇到的所有以前的资源并没有完全解决问题。

简而言之,我需要

  • 通过POST从登录http://client.foohttp://api.foo/login
  • 为用户提供提供logout路由的“已登录” GUI /组件状态
  • 用户注销/注销时能够“更新” UI。 这是最令人沮丧的
  • 保护我的路由以检查身份验证状态(他们是否需要),并将用户相应地重定向到登录页面

我的问题是

  • 每次导航到另一个页面时,我都需要打电话以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,
       ...
    }

我尝试过的

为什么我觉得自己迷失了方向

  • 似乎每个教程都依赖于某些数据库(许多Mongo,Couch,PHP + MySQL,无限广告)解决方案,并且没有一个纯粹依赖于与RESTful API的通信来保持登录状态。登录后,还会通过发送其他POST / GET withCredentials:true,所以这不是问题
  • 我找不到任何使用Angular + REST + Auth,没有后端语言的示例/教程/仓库。

我不太骄傲

诚然,我是Angular的新手,如果我以一种荒谬的方式来处理它,也不会感到惊讶。如果有人提出其他选择,我会很高兴-即使是汤到坚果。

我使用的Express主要是因为我真的很喜欢JadeStylus-我没有结婚的Express“路由和会放弃它,如果我想要做的是唯一可能与角的路由。

在此先感谢您提供任何帮助。而且请不要问我Google,因为我有大约26页的紫色链接。;-)


1该解决方案依赖于Angular的$ httpBackend模拟,并且尚不清楚如何使其与真实服务器对话。

2这是最接近的,但是由于我已有需要使用的API进行身份验证,因此无法使用护照的’localStrategy’,并且编写OAUTH服务似乎是 疯狂的
……只有我打算使用。


阅读 261

收藏
2020-07-04

共1个答案

一尘不染

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

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

角度安全性方面的主要关注点是路线安全性,幸运的是,在定义角度路线时,您要创建一个对象,该对象可以具有其他属性。我的方法的基础是在此路由对象中添加一个安全对象,该对象基本上定义了用户必须具有的角色才能访问特定路由。

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

整个方法围绕授权服务进行,该服务基本上进行检查以查看用户是否具有所需的权限。该服务将关注点从该解决方案的其他部分中抽象出来,以解决用户及其在登录期间可能已从服务器检索到的实际许可。虽然代码很冗长,但我的博客文章中已对其进行了详细说明。但是,它基本上处理许可检查和两种授权模式。第一个是用户必须至少具有定义的权限中的一个,第二个是用户必须具有所有定义的权限。

    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;
    };

现在,路由已具有安全性,您需要一种确定路线更改开始后用户是否可以访问该路由的方法。为此,我们拦截了路由更改请求,检查了路由对象(上面有我们的新访问对象),如果用户无法访问视图,我们将其替换为另一个视图。

    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()’,因为它将当前路由(他们没有权限查看的路由)替换为我们将其重定向到的路由。这将停止任何操作,然后导航回未经授权的路线。

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

解决方案的第二部分是能够根据那里的权限向用户隐藏/显示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);
                  }
              }
            };
        }]);

然后,您将确定像这样的元素:

 <button type="button" access="CanEditUser, Admin" access-permission-type="AtLeastOne">Save User</button>

阅读我的完整博客文章,以详细了解该方法。

2020-07-04