Когда текущий бэкенд отделен, обработка проблем с разрешениями немного отличается от нашей традиционной обработки. Автор как раз несколько дней назад руководил модулем управления правами проекта.Сейчас модуль управления правами завершен.Я хочу через 5-6 статей представить возникшие проблемы в проекте и свои решения.Надеюсь на это серия может дать своим друзьям некоторую помощь. Эта серия статей не является практическим руководством. В основном она знакомит с основными идеями и объясняет основной код. Партнеры по полному коду могут пометить и клонировать их на GitHub для изучения. Кроме того, изначальный план состоял в том, чтобы запустить проект и выложить в интернет для просмотра друзьям, но до покупки сервера в целях экономии памяти было всего 512М, и два приложения запустить не удалось (есть уже одноПроект с открытым исходным кодом V Tribeработает), поэтому вы можете только взглянуть на скриншоты ниже. На GitHub есть руководства по развертыванию, и вы также можете увидеть полный эффект при локальном развертывании.
адрес проекта:github.com/lenve/vhr
Если в предыдущих статьях мы в основном решили проблему на стороне сервера и инкапсулировали фронтенд-запрос, то в этой статье мы в основном говорим о входе в систему и динамической загрузке компонентов.
Эта статья является пятой статьей в этой серии.Рекомендуется сначала прочитать предыдущие статьи, чтобы лучше понять эту статью:
1.SpringBoot+Vue разделяет переднюю и заднюю части и использует SpringSecurity для идеального решения проблем с разрешениями (1)
2.SpringBoot+Vue разделяет переднюю и заднюю части и использует SpringSecurity для идеального решения проблем с разрешениями (2)
3.Соление пароля в SpringSecurity и обработка исключений в SpringBoot
4.Инкапсуляция запросов axios и унифицированная обработка исключений
Сохранить статус входа
После того, как пользователь успешно войдет в систему, информацию для входа в систему текущего пользователя необходимо сохранить локально для последующего использования. Конкретная реализация выглядит следующим образом:
Войти успешно сохранить данные
После успешного выполнения операции входа данные отправляются в хранилище через операцию фиксации.Основной код выглядит следующим образом:
this.postRequest('/login', {
username: this.loginForm.username,
password: this.loginForm.password
}).then(resp=> {
if (resp && resp.status == 200) {
var data = resp.data;
_this.$store.commit('login', data.msg);
var path = _this.$route.query.redirect;
_this.$router.replace({path: path == '/' || path == undefined ? '/home' : path});
}
});
store
Основной код магазина выглядит следующим образом:
export default new Vuex.Store({
state: {
user: {
name: window.localStorage.getItem('user' || '[]') == null ? '未登录' : JSON.parse(window.localStorage.getItem('user' || '[]')).name,
userface: window.localStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.localStorage.getItem('user' || '[]')).userface
}
},
mutations: {
login(state, user){
state.user = user;
window.localStorage.setItem('user', JSON.stringify(user));
},
logout(state){
window.localStorage.removeItem('user');
}
}
});
Чтобы уменьшить проблемы, данные после успешного входа пользователя в систему будут сохранены в localStorage (для предотвращения потери данных после того, как пользователь нажмет F5 для обновления), сохранены в виде строки и преобразованы в json при извлечении. Когда пользователь выходит и входит в систему, данные в localStorage очищаются.
Компоненты загружаются динамически
В модуле управления правами это ядро внешнего интерфейса.
основная идея
После успешного входа пользователя перед входом на домашнюю страницу на сервер отправляется запрос на получение текущей информации о меню и информации о компонентах.Сервер возвращает строку json в соответствии с ролью текущего пользователя и ресурсами, соответствующими роль в следующем формате:
[
{
"id": 2,
"path": "/home",
"component": "Home",
"name": "员工资料",
"iconCls": "fa fa-user-circle-o",
"children": [
{
"id": null,
"path": "/emp/basic",
"component": "EmpBasic",
"name": "基本资料",
"iconCls": null,
"children": [],
"meta": {
"keepAlive": false,
"requireAuth": true
}
},
{
"id": null,
"path": "/emp/adv",
"component": "EmpAdv",
"name": "高级资料",
"iconCls": null,
"children": [],
"meta": {
"keepAlive": false,
"requireAuth": true
}
}
],
"meta": {
"keepAlive": false,
"requireAuth": true
}
}
]
После того, как интерфейс получает эту строку, он делает две вещи: 1. Динамически добавляет json к текущему маршруту 2. Сохраняет данные в хранилище, а затем каждая страница отображает меню в соответствии с данными в хранилище.
Основная идея не сложна, давайте посмотрим на этапы реализации.
Время запроса данных
Это очень важно.
Некоторые друзья могут сказать, насколько это сложно.Можно ли сделать запрос после успешного входа в систему? Да, после успешного входа есть возможность запросить ресурс меню.После получения запроса мы сохраним его в магазине для следующего использования, но будет другая проблема.Если пользователь авторизуется успешно, нажмите на подстранице, войдите на подстраницу, а затем нажмите F5 для обновления, на этот раз это GG, потому что данные в магазине исчезают после обновления F5, и мы запрашиваем ресурсы меню только один раз при успешном входе в систему. Есть два пути решения этой проблемы: 1. Сохранять ресурсы меню не в хранилище, а в localStorage, чтобы данные оставались там даже после обновления F5 2. Непосредственно в смонтированном методе каждой страницы переходим на Загрузите ресурс меню один раз.
Так как ресурс меню очень чувствителен, то лучше не сохранять его локально, поэтому от схемы 1 отказываемся, но нагрузка по схеме 2 немного велика, поэтому я использую способ ее упрощения, и способ сделать это пользоваться навигацией в стороже маршрута.
навигационная охрана маршрута
Моя конкретная реализация такова: сначала создайте массив маршрутов в хранилище, который является пустым массивом, а затем включите глобальную защиту маршрутизации следующим образом:
router.beforeEach((to, from, next)=> {
if (to.name == 'Login') {
next();
return;
}
var name = store.state.user.name;
if (name == '未登录') {
if (to.meta.requireAuth || to.name == null) {
next({path: '/', query: {redirect: to.path}})
} else {
next();
}
} else {
initMenu(router, store);
next();
}
}
)
Код здесь очень короткий, позвольте мне дать простое объяснение: 1. Если страница, на которую вы хотите перейти, является страницей входа в систему, это ничего не говорит, просто перейдите напрямую.
2. Если это не страница входа, я сначала получаю текущий статус входа в магазин.Если я не вошел в систему, я буду использовать атрибут requireAuth метаатрибута в маршруте, чтобы определить, нужна ли страница, на которую я хочу перейти. для входа в систему. Если необходимо войти в систему, я вернусь на страницу входа в систему и передам путь к странице, на которую вы хотите перейти, в качестве параметра на страницу входа, чтобы вы могли перейти на целевую страницу. после успешного входа в систему. Если вам не нужно входить в систему, вы можете перейти напрямую (на самом деле, только страница входа в этом проекте не требует входа в систему); если вы уже вошли в систему, сначала инициализируйте меню, а потом прыгать.
Меню инициализации работает следующим образом:
export const initMenu = (router, store)=> {
if (store.state.routes.length > 0) {
return;
}
getRequest("/config/sysmenu").then(resp=> {
if (resp && resp.status == 200) {
var fmtRoutes = formatRoutes(resp.data);
router.addRoutes(fmtRoutes);
store.commit('initMenu', fmtRoutes);
}
})
}
export const formatRoutes = (routes)=> {
let fmRoutes = [];
routes.forEach(router=> {
let {
path,
component,
name,
meta,
iconCls,
children
} = router;
if (children && children instanceof Array) {
children = formatRoutes(children);
}
let fmRouter = {
path: path,
component(resolve){
if (component.startsWith("Home")) {
require(['../components/' + component + '.vue'], resolve)
} else if (component.startsWith("Emp")) {
require(['../components/emp/' + component + '.vue'], resolve)
} else if (component.startsWith("Per")) {
require(['../components/personnel/' + component + '.vue'], resolve)
} else if (component.startsWith("Sal")) {
require(['../components/salary/' + component + '.vue'], resolve)
} else if (component.startsWith("Sta")) {
require(['../components/statistics/' + component + '.vue'], resolve)
} else if (component.startsWith("Sys")) {
require(['../components/system/' + component + '.vue'], resolve)
}
},
name: name,
iconCls: iconCls,
meta: meta,
children: children
};
fmRoutes.push(fmRouter);
})
return fmRoutes;
}
В меню инициализации сначала определите, существуют ли данные в хранилище.Если они есть, значит, этот переход является обычным переходом, а не тем, что пользователь нажимает F5 или напрямую в адресной строке вводит адрес для входа. В противном случае перейдите в меню загрузки. Получив меню, сначала преобразуйте json, возвращаемый сервером, в формат, требуемый маршрутизатором, с помощью метода formatRoutes.Основная цель здесь — преобразовать компонент, потому что компонент, возвращаемый сервером, представляет собой строку, а то, что маршрутизатор needs — это компонент, поэтому мы можем динамически загружать необходимые компоненты в методе formatRoutes. После успешной подготовки формата данных, с одной стороны, данные сохраняются в хранилище, а с другой стороны, метод addRoutes в маршруте используется для их динамического добавления в маршрут.
рендеринг меню
Наконец, на главной странице получите меню json из магазина и преобразуйте его в меню. Соответствующий код можно найти вHome.vue
Проверьте это, без дальнейших церемоний.
ОК, после этого разные пользователи могут видеть разные меню после успешного входа в систему.
Подпишитесь на официальный аккаунт, чтобы вовремя получать свежие статьи: