Перехват действий 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 и покажите свое сообщение.