Для большинства управленческих фонов разрешения ролей являются важным звеном. С помощью настройки разрешений ролей мы можем легко настроить разрешения каждого модуля или страницы, принадлежащие каждому пользователю, чтобы пользователи могли получать доступ только к страницам с соответствующими разрешениями.
Проще говоря, какие страницы открыты для всех пользователей, к каким страницам можно получить доступ только после входа в систему, к каким можно получить доступ только с разрешениями роли xx и т. д. (здесь xx относится к администраторам, обычным участникам и т. д.) и т. д. на эти роли).
Дизайн схемы разрешений ролей в системе фонового управления очень важен.
- Во-первых, хороший дизайн может сэкономить много усилий для последующих модулей или страниц.
- Во-вторых, хороший дизайн может предоставить больше идей для обслуживания и дизайна для будущих функций расширения (таких как разрешение на управление определенной кнопкой и т. д.).
- В-третьих, хороший дизайн может сделать код более читабельным и позволяет с первого взгляда отличить код авторизации от бизнес-кода.
Для разрешений ролей настоящим привратником должен быть сервер. Во-первых, потому что соответствующая проверка кода внешнего интерфейса может быть пройдена путем мошенничества с данными, безопасность не высока. Во-вторых, интерфейс, вызываемый внешним интерфейсом в системе, не должен вызываться и возвращать данные без разрешения. Поэтому бэкенд интерфейса должен строго контролироваться в соответствии с разрешениями и остерегаться прямых вызовов без разрешения для получения возвращаемых данных. Короче говоря, даже если интерфейс не контролирует страницу и разрешения, пользователь не может получить соответствующие данные и операции страницы или модуля без разрешения.Бэкенд должен иметь возможность судить о том, что у него есть несанкционированный доступ, и отказать чтобы вернуть данные. Однако, если нет внешнего управления, работа всей системы будет очень плохой, например, различные отчеты об ошибках при доступе к неавторизованным страницам и т. Д.«Поэтому интерфейс должен иметь больше обязанностей в ролевых разрешениях, чтобы улучшить интерактивный опыт пользователя».
Во всем процессе управления разрешениями ролей все этапы внешнего интерфейса должны сначала отображать страницы по умолчанию, которые не требуют входа в систему (например, страницы 404, страницы входа, страницы регистрации), а затем вызывать внутренний интерфейс. при входе в систему или обновлении браузера, чтобы получить обратную связь.После получения данных о разрешениях вся система начинает генерировать отображаемый контент и навигацию по странице и, наконец, генерирует систему, которая отображает только соответствующие разрешения текущего Пользователь. Чтобы добиться контроля над всеми разрешениями роли. Подводя итог, можно сказать, что передняя часть в ролевых разрешениях должна нести большую ответственность за улучшение интерактивного взаимодействия с пользователем.
Из следующих трех аспектов опишите реализацию разрешений клиентской роли.
«Контроль разрешений на вход»
«Контроль доступа к ролям»
«Контроль прав на контент»
Контроль разрешений на вход
Коротко говоря, управление разрешениями на вход в систему заключается в том, чтобы понять, к каким страницам могут получить доступ пользователи, не вошедшие в систему, и к каким страницам можно получить доступ только после того, как пользователь войдет в систему.
Реализовать эту функцию также очень просто. Ниже перечислены две распространенные реализации.
1
Первый — собрать маршруты страниц, не требующие входа в систему, код выглядит следующим образом:
let invisible = [
{
path: '/login', //登录页面
name: 'Login',
component: Login,
},
{
path: '/404',
name: 'index-notFount',
component: () => import('@/pages/core/NotFount/index'),
},
];
export default invisible;
Определите невидимый массив, содержащий все маршруты страниц, которые можно просмотреть без входа в систему.
// 引入无需登录的页面
import invisible from './invisible';
let router = new Router({
routes: [
...invisible,
],
});
const invisibleMap = [];
invisible.forEach(item => {
if (item.name) {
invisibleMap.push(item.name);
}
});
router.beforeEach(async (to, from, next) => {
if (!invisibleMap.includes(to.name)) {
// 业务逻辑判断登录等
}
else {
next();
}
})
Вводится Invisible, имя маршрута сопоставляется с массивом invisibleMap, а решение перехватывается в функции защиты маршрута. Таким образом, страницы, не требующие входа в систему, можно просматривать напрямую (в невидимом массиве), а страницы, требующие входа в систему, будут подвергаться бизнес-оценкам, таким как вход в систему.
2
В дополнение к вышеуказанным методам вы также можете добавить метаданные к объекту маршрутизации, чтобы реализовать контроль разрешений страницы входа.Соответствующий код выглядит следующим образом:
export const routes = [
{
path: '/login', //登录页面
name: 'Login',
component: Login,
},
{
path:"/list", // 列表页
name:"List",
meta:{
need_login:true //需要登录
}
}
]
Код показан выше.Поскольку страница входа не требует входа в систему, нет необходимости устанавливать атрибут meta.need_login.Однако страница списка требует входа в систему, поэтому атрибут need_login установлен.
Как и в первом способе, настоящий перехват находится в роутинг гарде, код такой:
router.beforeEach((to, from, next) => {
if (to.meta.need_login) {
// 业务逻辑判断登录等
} else {
next();
}
});
Здесь получается поле need_login, и оценивается, является ли страница маршрутизации требующей входа в систему. Если да, то выполняется следующий шаг логики входа в систему.
Ролевой контроль доступа
Прежде чем обсуждать контроль разрешений ролей, мы должны прояснить один момент: в системе, которая вводит концепцию ролей, любая учетная запись в системе должна иметь по крайней мере одну или несколько ролевых удостоверений, чтобы учетная запись имела текущую роль (или несколько ролей). ) связанные функции разрешений. Короче говоря, мы даем разрешения не напрямую пользователям, а через роли. Управление разрешениями ролей в основном решает проблему предоставления разных разрешений разным ролям для предоставления разных разрешений учетным записям.Далее давайте разберемся с концепцией ролей.
В системе есть три общие роли: обычные участники, администраторы и суперадминистраторы. Обычные члены могут просматривать три модуля a, b и c системы, но они не могут просматривать и редактировать модули d и e (при условии, что можно редактировать только модули d и e). Администратор имеет все привилегии обычных участников, кроме того, он может просматривать d, e модули и редактировать d модули. У суперадминистратора есть все права этой системы, поэтому по сравнению с администратором здесь на один модуль редактирования больше.
Конечно, что касается вышеизложенного, то все это простое разделение ролей. Эта статья не делает здесь более глубокого обсуждения.
Итак, может ли в дизайне разрешения ролей доминировать над внешним интерфейсом? (То есть, задний конец идентифицирует учетную запись только как определенную роль, а разрешения контрольной роли доминируют над внешним интерфейсом)
Ответим на поставленный выше вопрос на простом примере.
На данный момент мы сделаем простой дизайн, основанный на более распространенных ролях, описанных выше.
export const permission = {
member:["Home"], //普通成员
admin:["Home" ,"Notify"], // 管理员
super_admin:["Home" ,"Notify","Manage"] // 超级管理员
}
Среди вышеперечисленных разрешений роли обычные участники имеют разрешения на домашнюю страницу, администраторы имеют разрешения на домашнюю страницу и уведомления, а суперадминистраторы имеют дополнительные разрешения на управление.
Если внешний интерфейс является доминирующим, внутренний интерфейс должен возвращать, к каким ролям принадлежит текущая учетная запись в интерфейсе входа. После получения роли учетной записи перейдите к указанному выше файлу конфигурации, чтобы получить разрешения страницы, к которым может получить доступ роль, а затем загрузите эту часть разрешений страницы в систему для достижения цели управления разрешениями (следует отметить что разрешения страницы в массиве равны. Значение должно совпадать с именем маршрута соответствующей страницы).
В приведенном выше дизайне серверная часть отвечает только за определение соответствующей роли для учетной записи, запись ее в библиотеку и возврат роли, соответствующей учетной записи, во внешний интерфейс при входе в систему. На этом этапе у некоторых студентов могут возникнуть сомнения: «Разве это не хорошо?» Внешний интерфейс также может управлять разрешениями ролей. Не волнуйтесь, давайте сейчас подумаем о проблеме."Если системному онлайн-проекту необходимо срочно добавить роль типа x, то фронтенду необходимо срочно модифицировать конфигурационный файл (конфигурационный файл такой, как показано выше), которого на данный момент недостаточно, а предыдущий y пользователя нужно переместить на х под роль, то не только фронтенду нужно изменить конфигурационный файл, но и бэкенду нужно переместить пользователя у на роль х в библиотеке.Такие изменения очень ошибочны склонны и сложны».
Подводя итог, с точки зрения разрешений ролей, на самом деле, лучший способ - предоставить серверной части возможность настроить, какие роли и каким ролям соответствует учетная запись.Эта логика должна быть обязанностью серверной части, и серверная часть напрямую возвращает право владения учетной записью путем входа в систему. Основная обязанность внешнего интерфейса должна заключаться в возврате в соответствии с разрешениями внутреннего интерфейса и отображении соответствующих страниц разрешений и меню. Таким образом, даже если встречается вышеупомянутая модификация, ее можно решить легко и ловко.
Ниже описаны сценарии для разрешений роли.
Например, структура разрешений учетной записи, возвращаемая серверной частью, выглядит следующим образом.
{
"home": {
"id":"100",
"name":"home",
"desc":"首页",
"value":true,
"children": [],
}
}
В этой структуре разрешений id — это уникальный идентификационный идентификатор страницы или модуля, имя здесь предпочтительно соответствует значению имени внешнего объекта страницы маршрутизации, desc — это имя, отображаемое в меню, а значение представляет, модуль или отображается страница или нет, дочерний массив является вторичным массивом страниц этой страницы, который оказывает важное влияние на контроль разрешений маршрута, а также на рендеринг и создание меню.
В этой структуре внешний интерфейс определяет, имеет ли страница разрешение на отображение, оценивая значение.Дочерними элементами являются текущая страница или страница второго уровня под модулем, страница третьего уровня и т. д. как дома. Если значение страницы первого уровня равно false, то второй и третий уровни ниже не должны иметь права на отображение.
В это время передняя часть должна рекурсивно пройти структуру, возвращенную задней частью, и, когда значение будет признано ложным, отфильтровать соответствующую страницу маршрутизации.
// 生成过滤路由和菜单的方法
function filterRouter(arr, obj, type) {
if (Array.isArray(obj)) {
// 数组处理
obj.forEach(item => {
handleRouterItem(arr, item, type);
});
} else {
// 对象处理
for (let item in obj) {
handleRouterItem(arr, obj[item], type);
}
}
}
// 处理每个元素节点
function handleRouterItem(arr, item, type) {
// 确定这个页面或模块是不展示的
if (item.value === false) {
if (type === 'menu') {
assistance(arr, routerMap[item.name]);
} else {
assistanceRouter(arr, routerMap[item.name]);
}
} else if (item.childrens && item.childrens.length > 0) {
filterRouter(arr, item.childrens, type);
}
}
function assistanceRouter(arr, name, obj) {
for (let i = 0; i < arr.length; i++) {
if (arr[i].name === name) {
// 无权限页面设置meta字段或者直接删除
// arr.splice(i, 1);
Vue.prototype.$set(arr[i].meta, 'hasRoleAuth', false);
return true;
} else {
if (arr[i].children && arr[i].children.length > 0) {
if (assistanceRouter(arr[i].children, name, arr[i])) {
return;
}
}
}
}
}
function assistance(arr, name, obj) {
for (let i = 0; i < arr.length; i++) {
if (arr[i].name === name) {
arr.splice(i, 1);
return true;
} else {
if (arr[i].children && arr[i].children.length > 0) {
if (assistance(arr[i].children, name, arr[i])) {
return;
}
}
}
}
}
export const rolePermission = () => {
// router为所有页面的路由结构,roleRouter为后端返回的角色权限对象
filterRouter(router, roleRouter);
router.addRoutes(router);
}
В приведенном выше коде router — это массив объектов маршрутизации внешнего интерфейса, а roleRouter — соответствующая структура данных разрешений ролей, принадлежащих учетной записи, возвращаемой серверной частью.
В функции filterRouter просмотрите каждый элемент в структуре данных roleRouter и передайте логику обработки каждого элемента в handleRouterItem.
В функции HandlerItemItem определяется, является ли поле значения каждого элемента ложным.Если ложное значение является ложным, модуль или страница не отображают разрешения. Затем вы должны быть переданы AssistanceRerouter и Assistance отфильтровать модуль или страницу.
В функциях AssistanceRouter и Assistance их основная функция — найти объект маршрутизации, значение имени которого совпадает с именем параметра в объекте маршрутизации массива, а в функции AssistanceRouter он помечен полем hasRoleAuth в метаобъекте, который означает отсутствие полномочий Доступ к разрешениям маршрутизации также можно фильтровать, как и функцию помощи. В помощь фильтрация несанкционированных страниц используется для генерации меню.
Вышеупомянутый метод представляет собой метод рекурсивного обхода поля разрешений серверной части и фильтрации существующей структуры маршрутизации для создания структуры маршрутизации и меню, соответствующих разрешению.
Таким образом, пользователь может получить доступ и просмотреть соответствующую страницу только в соответствии с правилами разрешений в соответствующем списке разрешений.
Лучше всего инкапсулировать эту часть кода для динамического добавления разрешения роли маршрутизации, потому что его нужно вызывать, когда пользователь входит в систему и обновляет страницу.
Выйти и сменить пользователя
В системе, которая вводит ролевые разрешения, также очень важно выходить из системы и переключать пользователей. Потому что разные учетные записи часто имеют разные разрешения. Поэтому следует уделить особое внимание тому, чтобы не вносить информацию о разрешении предыдущей учетной записи при выходе и переключении учетных записей, иначе могут возникнуть серьезные лазейки.
Итак, какие решения мы можем принять для выхода и выхода из ролевых разрешений?
Есть два решения.
Первое решение заключается в том, что пользователь обновляет браузер после выхода из системы или переключения учетных записей, но это решение может привести к менее удобному интерфейсу.
Второе решение — инициализировать соответствующий экземпляр маршрутизации после выхода пользователя Код выглядит следующим образом:
import Router from 'vue-router';
import router from '@/router';
import store from '@/store/index.js';
import invisible from '@/router/invisible';
export const resetRouter = () => {
let newRouter = new Router({
routes: [...invisible],
});
router.matcher = newRouter.matcher;
store.commit('CLEAR_ROLE_AUTH');
};
Инициализируйте динамическую маршрутизацию текущей учетной записи, а также очистите информацию о разрешениях текущей роли в vuex.
Контроль прав на контент
В ролевых разрешениях из предыдущей части это позволяет разным учетным записям получать доступ к разным страницам, но иногда необходимо более деликатно управлять элементом на странице, например добавлять, удалять и изменять кнопку одну за другой. , Необходимо сделать контроль разрешений контента для содержимого страницы.
В этой статье мы просто используем добавления, удаления и модификации в качестве разрешений на контент для управления контентом.
После общения возвращаемая структура бэкенда теперь должна выглядеть так:
{
"home": {
"id":"100",
"name":"home",
"desc":"首页",
"value":true,
"children": [],
"options": {
"create": true,
"delete": true,
"update": true,
}
}
}
В текущей структуре есть три элемента управления разрешениями контента на главной странице, а именно создание, удаление и обновление (если вам нужно добавить новые, вы можете добавить их в опции после общения с бэкендом).
После получения такой структуры данных нам нужно разработать схему, чтобы связать эту структуру разрешений с содержимым страницы Здесь мы используем инструкции. Мы создаем глобальное пользовательское разрешение директивы, псевдокод выглядит следующим образом:
import router from '@/router';
import store from '@/store';
app.directive('permission', {
mounted(el, binding, vnode) {
const permission = binding.value; // 获取指令值
const current_page = router.currentRoute.value.name; // 获取当前路由名称
const options = getOptions(current_page) // getOptions方法为拿到路由名称对应的角色权限对象
if (!options[permission]) {
el.parentElement.removeChild(el); // 没有该内容权限
}
},
});
В приведенном выше коде сначала получите значение инструкции, затем получите текущее имя маршрута, получите соответствующие объекты в структуре данных разрешения роли, соответствующей имени маршрута, с помощью метода getOptions, а затем оцените, есть ли разрешение содержимого в параметрах, если нет, то удалите дом.
В html директивы используются следующим образом:
<template>
<div>
<button v-permission="'create'">创建</button>
<button v-permission="'update'">修改</button>
<button v-permission="'delete'">删除</button>
</div>
</template>
Короче говоря, это связать соответствующую структуру данных разрешений ролей и DOM с помощью инструкций.
Для особых бизнес-сценариев, таких как путаница стилей после сокрытия, несогласованность дизайна пользовательского интерфейса и т. д. В это время вы должны определить, следует ли скрывать или отображать подсказку без разрешения в соответствии с потребностями проекта.Мы не будем делать слишком много описания в этой статье.
«Контроль разрешений во внешнем интерфейсе должен быть больше для оптимизации взаимодействия с пользователем. Кроме того, он также усиливает уровень защиты приложения, но следует отметить, что соответствующая проверка внешнего интерфейса может быть взломана техническими средствами. средства. Однако проблема разрешений связана с программным обеспечением. Сохранность всех данных в системе».
Поэтому, чтобы обеспечить бесперебойную работу системы, и интерфейс, и сервер должны защищать свои разрешения.