Как спроектировать маршрутизацию авторизации на основе ресурсов angularJS?

Я создаю систему блогов с использованием angularJS и теперь пытаюсь создать поток авторизации ресурсов, который прост в использовании для определенных ресурсов. Например, у меня есть следующие состояния PROPOSALITEM, PROPOSALITEM.VIEW и PROPOSALITEM.EDIT. PROPOSALITEM — это родительские состояния, которые разрешают предложениеItem с помощью предоставленного :proposalId для дочерних состояний. PROPOSALITEM.VIEW — это состояние просмотра, которое позволяет всем пользователям получать к нему доступ, а PROPOSALITEM.EDIT — это страница редактирования, которая должна разрешать доступ только proposal owner.

Я обнаружил, что есть красивая структура для выполнения потока авторизации на основе role в angularJS из этой статьи: " rel="nofollow">Методы аутентификации в приложениях AngularJS. Однако то, что мне сейчас нужно, основано на владении ресурсом, чтобы решить, может ли пользователь получить доступ к маршруту. И у меня есть много ресурсов, таких как модель proposal, которые нужно проверять с авторизацией владельца. Все эти модели снабжены столбцом owner. Есть ли какое-то общее решение для решения этой проблемы? (Я не хочу размещать код авторизации для каждой модели в отдельной части разрешения, потому что это сложно поддерживать)

/* Abstract states. Resolve proposalItem */
.state('PROPOSALITEM', {
    abstract: true,
    url: '/proposals/:proposalId',
    template: '<ui-view/>',
    resolve: {
        proposalItem: function($stateParams, ProposalDataService) {
            return ProposalDataService.getItem($stateParams.proposalId);
        }
    }
})
/* View states. Allows all users to access */
.state('PROPOSALITEM.VIEW', {
    abstract: true,
    url: '/view',
    template: '...'
})
/* Edit states. Allows only the proposal owner */
.state('PROPOSALITEM.EDIT', {
    url: '/edit',
    template: '...',
    resolve: {
        proposalItem: function($q, proposalItem, UserDataService) {
            var me = UserDataService.getMe();
            // me: {
            //     _id: '1',
            //     name: '...'
            // }
            if (proposalItem.owner._id === me._id) {
                // Authorized.
                return proposalItem;
            } else {
                // Not authorized.
                var deferred = $q.defer();
                deferred.reject(ERROR_KEYS.NOT_AUTHORIZED);
                return deferred.promise;
            }
        }
    }
})

person Huang Yen-Chieh    schedule 25.01.2015    source источник
comment
Это очень хороший и важный вопрос. На самом деле у меня есть рабочее решение для этого, но мне нужно извлечь его из моего приложения в виде модуля, прежде чем я смогу его опубликовать. Я планирую сделать это к концу следующей недели, хотя не уверен, что вы готовы ждать.   -  person appmux    schedule 25.01.2015
comment
Даже я был бы рад узнать это. @appmux   -  person micronyks    schedule 25.01.2015
comment
@appmux Я не тороплюсь. Очень ждем вашего решения!   -  person Huang Yen-Chieh    schedule 25.01.2015


Ответы (1)


Вот как я обычно поступаю в этом случае. Создайте сервис, который должен заниматься аутентификацией:

yourapp.factory('YourResourcePermission', function () {
    return {
        check: function (resource) {
            var me = UserDataService.getMe();
            // return a promise which is resolved with the data
            // if the user has permission, or rejected otherwise.
        }
    };
});

Затем вы используете этот сервис в качестве параметра разрешения для нужного вам статуса:

.state('PROPOSALITEM.EDIT', {
url: '/edit',
template: '...',
resolve: function (proposalItem, YourResourcePermission) {  
    return YourResourcePermission.check(proposalItem);
}

})

Таким образом, вы можете хранить всю свою логику разрешений отдельно от маршрутов в выделенной (и многократно используемой) службе.

Если у вас есть несколько состояний, требующих одного и того же стандартного шаблона, вы можете использовать Angular $provide.decorator для автоматического внедрения пользовательской логики в ваши состояния. См. это: https://github.com/christopherthielen/ui-router-extras/blob/master/src/dsr.js#L10 и этот https://stackoverflow.com/a/26848546/3794660 в качестве ссылок на то, как вы можете украсить $stateProvider и создать свой собственный тип состояния, в котором уже установлен параметр «разрешить».

Надеюсь, это полезно.

person fabio.sussetto    schedule 14.02.2015