Перехват действий GSP Grails на стороне клиента или сервера

Grails 2.4.5 здесь. Я пытаюсь реализовать следующее поведение UX для своих GSP:

  • Если пользователь имеет право нажимать кнопку, тогда они могут это сделать; Однако
  • Если пользователь не имеет права нажимать кнопку, тогда, когда они нажимают кнопку, в верхней части экрана появляется баннерное сообщение (flash?) с розовым/розоватым/красным фоном, в котором говорится: "Вы не знаете, t иметь разрешение на выполнение этого действия

Чтобы определить, имеет ли пользователь требуемое разрешение, у меня есть доступ к функциям как из слоев Groovy, так и для слоев GSP/taglib.

С уровня Groovy/controller:

SecurityUtils.hasPermission(String permission)
Ex: SecurityUtils.hasPermission('UPDATE_BUZZ')

Из слоя GSP/taglib:

<sec:hasPermission permission="<permission name>">???</sec:hasPermission>
Ex: <sec:hasPermission permission="UPDATE_BUZZ">???</sec:hasPermission>

Итак, учитывая эти два доступных механизма проверки доступа и учитывая следующий контроллер:

class FizzController {
    BuzzService BuzzService

    def buzz() {
        SomeData dataModel = buzzService.getModel(params)
        render(view: 'buzz', model: [ dataModel: dataModel ])
    }
}

... где buzz.gsp:

<!-- Lots of HTML/GSP here -->
<g:submitButton name="update" value="Update" />
<!-- Lots more HTML/GSP down here -->

Учитывая все это, мой вопрос: Как/где я должен: (1) ответить на кнопку "update", обработчик кликов, (2) выполнить проверку доступа и (3) отобразить ошибку /banner/flash message Пример кода (даже псевдокод) был бы самым потрясающим!

Ответ 1

Я предполагаю по вашему вопросу, что вы не хотите обновлять страницу и, возможно, даже не аякс-вызов. Потому что если вы это сделали, то показывать баннер не сложно. Вы просто хотите, чтобы это вел себя как проверка на стороне клиента JavaScript (UX-мудрый). Если это предположение неверно, не читайте и не используйте решение Aramiti. Иначе идти вперед.

Первое решение

Вы можете создать тег, который принимает разрешение в качестве ввода. Что-то вроде

<myTagLib:flashOnNoPermission permission="PERM" name="name" value="value">
</myTagLib:flashOnNoPermission>

Это определение тега может проверить разрешение с помощью sec:hasPermission. Затем этот тег может просто отобразить шаблон, содержащий что-то вроде этого

<hidden flash message>
<g:submitButton name="name" value="value" onclick="<unhide flash if no permission>"/>

В основном создайте обертку над кнопкой grails, чтобы вы могли иметь флэш-сообщения вместе с кнопками.

Проблема

  • Что делать, если пользовательские права изменяются, когда пользователь находится на экране? Ajax заботится об этом, но это не так. После загрузки экрана все исправлено.
  • Баннер вместе с кнопкой

Второе решение

Добавьте общий div в верхней части макета для отображения флэш-сообщений. Затем создайте тег, аналогичный приведенному выше. Просто не добавляйте флэш-сообщение в визуализированный шаблон. Что-то вроде

    <g:submitButton name="name" value="value" onclick="<unhide flash at top of layout if no permission>"/>

Проблема

  • Что делать, если права пользователя изменены, когда он находится на экране?

Не уверен, зачем вам нужны обработчики onclick, но если нет оснований для решения Aramiti.

Ответ 2

Вот что я хотел бы предложить:

  • Убедитесь, что ваш метод контроллера основан на ролях
  • Удалите проверку прав в GSP, если кнопка должна быть видимой для всех
  • Создайте вызов AJAX при отправке, если статус ответа равен 403, отобразите баннер.

Ответ 3

Если бы я был вами, я бы, вероятно, попытался использовать фильтр перед действием в этом случае. В этом фильтре я бы сделал проверку, если текущий пользователь имеет разрешения на такое действие (проверка разрешений всегда должна выполняться на стороне сервера из-за соображений безопасности), а не:

  • если проверка безопасности проходит - просто верните true (контроллер продолжит поток)

  • если проверка безопасности не удалась - вы можете использовать flash.message по умолчанию и вернуть false (с соответствующим флаговым сообщением типа CSS может отображаться в верхней части экрана с розовым/розоватым/красным фоном)

Пример кода:

class UserFilters {
   def filters = {
      // ... other filters ...
      permissionAllCheck(controller: '*', action: '*') {
         before = {
            doPermissionCheck(delegate)
         }
      }
   }

   private boolean doPermissionCheck(filters) {
         if (! YourService.checkForPermissionForCurrentlyLoggedUser()) {
            filters.flash.message = "You don't have permission to take this action"
            return false
         }
      true
   }
}

Если вы хотите использовать фильтр только для конкретного контроллера/действия, отметьте applying раздел. Помните также, что вы можете использовать фильтр правил инвертирования.

Дополнительная информация о различных filterTypes.

Вы также должны помнить о добавлении раздела flash.message к вашему макету (или выбранным представлениям). Вы всегда можете указать тип сообщения Flash и стиль css.

Ответ 4

Лучшим способом было бы скрыть кнопку, если у пользователя нет разрешения на ее использование. Это можно легко достичь с помощью <sec:hasPermission permission="UPDATE_BUZZ">button</sec:hasPermission>

Если вы хотите, чтобы кнопка отображалась даже для пользователя без разрешения, вы можете использовать тот же hasPermission, чтобы добавить дополнительный класс к кнопке. Теперь захватите событие синхронизации для этого класса с помощью jQuery и покажите свое сообщение.