基于经过身份验证的用户权限隐藏/显示AngularJS或任何其他单页面应用程序组件的正确方法是什么?

时间:2014-06-26 18:14:33

标签: angularjs spring-mvc spring-security authorization

我有一个应用程序使用 Spring Security 进行服务器端身份验证/授权, Spring MVC 用于 REST 服务器端端点,以及AngularJS观点。

在服务器端,我已经实现了根据用户权限访问所有这些REST端点所需的所有过滤器。 我的问题是,如何基于经过身份验证的USER 权限来制作可见/隐藏html元素

例如我在视图中有3个按钮( button1,button2,button3 )。每个按钮都有一个对应的 USER RIGHT ,这样可以使它们可见/隐藏。我们称之为权利 USER_RIGHT1,USER_RIGHT2,USER_RIGHT3

如果用户有正确的 USER_RIGHT1 ,他应该在视图中看到 button1 ,如果他有正确的 USER_RIGHT2 ,他应该看到查看 button2 ,等等。

我的方法是在客户端中列出经过身份验证的用户权限,并执行以下示例:

<div ng-if="rights contains USER_RIGHT1">
    <button name="button1".... />
</div>
<div ng-if="rights contains USER_RIGHT2">
    <button name="button2".... />
</div>

我不确定经过身份验证的用户权限列表是否应该在客户端中。

我该如何处理这个问题?我做得对吗?

3 个答案:

答案 0 :(得分:12)

我的方法基本上就是你的建议。

您可以拥有一个存储用户权限数组的工厂,并且具有检查权限是否在数组中的功能:

.factory('Auth', function() {

var permissions = [];

return {
    allowed : function(permission) {

        return _.contains(permissions, permission);
    }
};});

然后你可以有一个使用服务显示/隐藏元素的指令:

.directive('allowed', function(Auth){

    return {

        link : function(scope, elem, attr) {

            if(!Auth.allowed(attr.allowed)){
                elem.hide();
            }
        }
    };
});

所以在你的观点中你只需要这样做:

<div allowed="permission_name"> </div>

答案 1 :(得分:9)

客户端上的安全性,即在浏览器中的安全性是无用的。但是,它应该存在以阻止普通用户看到他们不应该看到的东西,但是服务器应该是安全性最终的地方。

我创建了一个快速指令来执行显示/隐藏或UI组件,并拥有一个身份验证服务来执行实际逻辑以确定用户是否具有正确的权限。

在我的博客上写一篇关于AngularJS授权的深度文章,我实际上约有60%的时间。我会在大约一周内检查一下,我应该完成检查 - 它也可以帮助你进行路线授权。

更新:可以找到关于角度路线授权和安全性的博客文章here

基本上,授权服务会授权用户使用您的后端服务,然后存储他们的应用程序权限。

然后,该指令将使用此服务来确定用户是否有足够的权限查看UI组件。

我还没有对以下代码进行测试,因此您可能需要对其进行调试。

    angular.module('myApp').factory('authService', [
    function () {
        var loggedInUser,
            login = function (email, password) {
                //call server and rights are returned
                //loggedInUser is assigned
            },
            hasSecurityRoles = function (requiredRoles) {
                var hasRole = false,
                    roleCheckPassed = false,
                    loweredRoles;
                if (loggedInUser === undefined) {
                    hasRole = false;
                } else if (loggedInUser !== undefined && requiredRoles === undefined) {
                    hasRole = true;
                } else if (loggedInUser !== undefined && requiredRoles !== undefined) {
                    if (requiredRoles.length === 0) {
                        hasRole = true;
                    } else if (loggedInUser.permittedActions === undefined) {
                        hasRole = false;
                    } else {
                        loweredRoles = [];
                        angular.forEach(loggedInUser.permittedActions, function (role) {
                            loweredRoles.push(role.name.toLowerCase());
                        });

                        // check user has at least one role in given required roles
                        angular.forEach(requiredRoles, function (role) {
                            roleCheckPassed = roleCheckPassed || _.contains(loweredRoles, role.toLowerCase());
                        });

                        hasRole = roleCheckPassed;
                    }
                }

                return hasRole;
            };

        return {
            login: login,
            hasSecurityRoles: hasSecurityRoles
        };
    }
]);

    angular.module('myApp').directive('visibleToRoles', [
        'authService',
        function (authService) {
            return {
                link: function (scope, element, attrs) {
                    var makeVisible = function () {
                            element.removeClass('hidden');
                        },
                        makeHidden = function () {
                            element.addClass('hidden');
                        },
                        determineVisibility = function (resetFirst) {
                            if (resetFirst) {
                                makeVisible();
                            }

                            if (authService.hasSecurityRoles(roles)) {
                                makeVisible();
                            } else {
                                makeHidden();
                            }
                        },
                        roles = attrs.visibleToRoles.split(',');


                    if (roles.length > 0) {
                        determineVisibility(true);
                    }
                }
            };
        }
    ]);

然后你会像这样使用它

<div visible-to-role="admin,usermanager">.....</div>

答案 2 :(得分:1)

您可以从服务器中检索经过身份验证的用户权限列表,然后将其加载到您的范围内,然后执行您正在执行的操作,而不是在模板/页面中使用硬编码列表。 如果您使用的是ui-router,则可以使用resolve属性(即在调用控制器之前可能从服务器预加载某些数据)。

这样,您只能检索正在查看该页面的用户的权限,而不是在客户端中对所有权限进行硬编码。