refactor(projects): 动态路由权限完善

This commit is contained in:
Soybean
2022-04-29 02:00:51 +08:00
parent 401f0c748d
commit 55ddc9cab0
36 changed files with 406 additions and 717 deletions

View File

@ -1,9 +1,10 @@
import type { MockMethod } from 'vite-plugin-mock';
import { userModel } from '../model';
const token: ApiAuth.Token = {
token: '__TEMP_TOKEN__',
refreshToken: '__TEMP_REFRESH_TOKEN__'
};
/** 参数错误的状态码 */
const ERROR_PARAM_CODE = 10000;
const ERROR_PARAM_MSG = '参数校验失败!';
const apis: MockMethod[] = [
// 获取验证码
@ -18,73 +19,107 @@ const apis: MockMethod[] = [
};
}
},
// 密码登录
// 用户+密码 登录
{
url: '/mock/loginByPwd',
url: '/mock/login',
method: 'post',
response: (): Service.MockServiceResult<ApiAuth.Token> => {
return {
code: 200,
message: 'ok',
data: token
};
}
},
// 验证码登录
{
url: '/mock/loginByCode',
method: 'post',
response: (): Service.MockServiceResult<ApiAuth.Token> => {
return {
code: 200,
message: 'ok',
data: token
};
}
},
// 获取用户信息(请求头携带token)
{
url: '/mock/getUserInfo',
method: 'get',
response: (): Service.MockServiceResult<ApiAuth.UserInfo> => {
return {
code: 200,
message: 'ok',
data: {
userId: '0',
userName: 'Soybean',
userPhone: '15170283876',
userRole: 'super'
}
};
}
},
{
url: '/mock/testToken',
method: 'post',
response: (option: Service.MockOption): Service.MockServiceResult<true | null> => {
if (option.headers?.authorization !== token.token) {
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.Token | null> => {
const { userName = undefined, password = undefined } = options.body;
if (!userName || !password) {
return {
code: 66666,
message: 'token 失效',
code: ERROR_PARAM_CODE,
message: ERROR_PARAM_MSG,
data: null
};
}
const findItem = userModel.find(item => item.userName === userName && item.password === password);
if (findItem) {
return {
code: 200,
message: 'ok',
data: {
token: findItem.token,
refreshToken: findItem.refreshToken
}
};
}
return {
code: 200,
message: 'ok',
data: true
code: 1000,
message: '用户名或密码错误!',
data: null
};
}
},
// 获取用户信息(请求头携带token, 根据token获取用户信息)
{
url: '/mock/getUserInfo',
method: 'get',
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.UserInfo | null> => {
// 这里的mock插件得到的字段是authorization, 前端传递的是Authorization字段
const { authorization = '' } = options.headers;
const REFRESH_TOKEN_CODE = 66666;
if (!authorization) {
return {
code: REFRESH_TOKEN_CODE,
message: '用户已失效或不存在!',
data: null
};
}
const userInfo: Auth.UserInfo = {
userId: '',
userName: '',
userRole: 'user'
};
const isInUser = userModel.some(item => {
const flag = item.token === authorization;
if (flag) {
const { userId: itemUserId, userName, userRole } = item;
Object.assign(userInfo, { userId: itemUserId, userName, userRole });
}
return flag;
});
if (isInUser) {
return {
code: 200,
message: 'ok',
data: userInfo
};
}
return {
code: REFRESH_TOKEN_CODE,
message: '用户信息异常!',
data: null
};
}
},
{
url: '/mock/updateToken',
method: 'post',
response: (): Service.MockServiceResult<ApiAuth.Token> => {
response: (options: Service.MockOption): Service.MockServiceResult<ApiAuth.Token | null> => {
const { refreshToken = '' } = options.body;
const findItem = userModel.find(item => item.refreshToken === refreshToken);
if (findItem) {
return {
code: 200,
message: 'ok',
data: {
token: findItem.token,
refreshToken: findItem.refreshToken
}
};
}
return {
code: 200,
message: 'ok',
data: token
code: 3000,
message: '用户已失效或不存在!',
data: null
};
}
}

View File

@ -1,403 +1,26 @@
import type { MockMethod } from 'vite-plugin-mock';
import { filterAuthRoutesByUserPermission } from '../utils';
const routes: AuthRoute.Route[] = [
{
name: 'dashboard',
path: '/dashboard',
component: 'basic',
children: [
{
name: 'dashboard_analysis',
path: '/dashboard/analysis',
component: 'self',
meta: {
title: '分析页',
requiresAuth: true,
icon: 'icon-park-outline:analysis'
}
},
{
name: 'dashboard_workbench',
path: '/dashboard/workbench',
component: 'self',
meta: {
title: '工作台',
requiresAuth: true,
permissions: ['super', 'admin'],
icon: 'icon-park-outline:workbench'
}
}
],
meta: {
title: '仪表盘',
icon: 'carbon:dashboard',
order: 1
}
},
{
name: 'document',
path: '/document',
component: 'basic',
children: [
{
name: 'document_vue',
path: '/document/vue',
component: 'self',
meta: {
title: 'vue文档',
requiresAuth: true,
icon: 'mdi:vuejs'
}
},
{
name: 'document_vue-new',
path: '/document/vue-new',
component: 'self',
meta: {
title: 'vue文档(新版)',
requiresAuth: true,
icon: 'mdi:vuejs'
}
},
{
name: 'document_vite',
path: '/document/vite',
component: 'self',
meta: {
title: 'vite文档',
requiresAuth: true,
icon: 'simple-icons:vite'
}
},
{
name: 'document_project',
path: '/document/project',
meta: {
title: '项目文档(外链)',
requiresAuth: true,
icon: 'mdi:file-link-outline',
href: 'https://docs.soybean.pro/'
}
}
],
meta: {
title: '文档',
icon: 'carbon:document',
order: 2
}
},
{
name: 'component',
path: '/component',
component: 'basic',
children: [
{
name: 'component_button',
path: '/component/button',
component: 'self',
meta: {
title: '按钮',
requiresAuth: true,
icon: 'ic:baseline-radio-button-checked'
}
},
{
name: 'component_card',
path: '/component/card',
component: 'self',
meta: {
title: '卡片',
requiresAuth: true,
icon: 'mdi:card-outline'
}
},
{
name: 'component_table',
path: '/component/table',
component: 'self',
meta: {
title: '表格',
requiresAuth: true,
icon: 'mdi:table-large'
}
}
],
meta: {
title: '组件示例',
icon: 'fluent:app-store-24-regular',
order: 3
}
},
{
name: 'plugin',
path: '/plugin',
component: 'basic',
children: [
{
name: 'plugin_map',
path: '/plugin/map',
component: 'self',
meta: {
title: '地图',
requiresAuth: true,
icon: 'mdi:map'
}
},
{
name: 'plugin_video',
path: '/plugin/video',
component: 'self',
meta: {
title: '视频',
requiresAuth: true,
icon: 'mdi:video'
}
},
{
name: 'plugin_editor',
path: '/plugin/editor',
component: 'multi',
children: [
{
name: 'plugin_editor_quill',
path: '/plugin/editor/quill',
component: 'self',
meta: {
title: '富文本编辑器',
requiresAuth: true,
icon: 'mdi:file-document-edit-outline'
}
},
{
name: 'plugin_editor_markdown',
path: '/plugin/editor/markdown',
component: 'self',
meta: {
title: 'markdown编辑器',
requiresAuth: true,
icon: 'ri:markdown-line'
}
}
],
meta: {
title: '编辑器',
icon: 'icon-park-outline:editor'
}
},
{
name: 'plugin_swiper',
path: '/plugin/swiper',
component: 'self',
meta: {
title: 'Swiper插件',
requiresAuth: true,
icon: 'simple-icons:swiper'
}
},
{
name: 'plugin_copy',
path: '/plugin/copy',
component: 'self',
meta: {
title: '剪贴板',
requiresAuth: true,
icon: 'mdi:clipboard-outline'
}
},
{
name: 'plugin_icon',
path: '/plugin/icon',
component: 'self',
meta: {
title: '图标',
requiresAuth: true,
icon: 'ic:baseline-insert-emoticon'
}
},
{
name: 'plugin_print',
path: '/plugin/print',
component: 'self',
meta: {
title: '打印',
requiresAuth: true,
icon: 'ic:baseline-local-printshop'
}
}
],
meta: {
title: '插件示例',
icon: 'clarity:plugin-line',
order: 4
}
},
{
name: 'auth-demo',
path: '/auth-demo',
component: 'basic',
children: [
{
name: 'auth-demo_permission',
path: '/auth-demo/permission',
component: 'self',
meta: {
title: '权限切换',
requiresAuth: true,
icon: 'ic:round-construction'
}
},
{
name: 'auth-demo_super',
path: '/auth-demo/super',
component: 'self',
meta: {
title: '超级管理员可见',
requiresAuth: true,
permissions: ['super'],
icon: 'ic:round-supervisor-account'
}
}
],
meta: {
title: '权限示例',
icon: 'ic:baseline-security',
order: 5
}
},
{
name: 'exception',
path: '/exception',
component: 'basic',
children: [
{
name: 'exception_403',
path: '/exception/403',
component: 'self',
meta: {
title: '异常页403',
requiresAuth: true,
icon: 'ic:baseline-block'
}
},
{
name: 'exception_404',
path: '/exception/404',
component: 'self',
meta: {
title: '异常页404',
requiresAuth: true,
icon: 'ic:baseline-web-asset-off'
}
},
{
name: 'exception_500',
path: '/exception/500',
component: 'self',
meta: {
title: '异常页500',
requiresAuth: true,
icon: 'ic:baseline-wifi-off'
}
}
],
meta: {
title: '异常页',
icon: 'ant-design:exception-outlined',
order: 6
}
},
{
name: 'multi-menu',
path: '/multi-menu',
component: 'basic',
children: [
{
name: 'multi-menu_first',
path: '/multi-menu/first',
component: 'multi',
children: [
{
name: 'multi-menu_first_second',
path: '/multi-menu/first/second',
component: 'self',
meta: {
title: '二级菜单',
requiresAuth: true,
icon: 'ic:outline-menu'
}
},
{
name: 'multi-menu_first_second-new',
path: '/multi-menu/first/second-new',
component: 'multi',
children: [
{
name: 'multi-menu_first_second-new_third',
path: '/multi-menu/first/second-new/third',
component: 'self',
meta: {
title: '三级菜单',
requiresAuth: true,
icon: 'ic:outline-menu'
}
}
],
meta: {
title: '二级菜单(有子菜单)',
icon: 'ic:outline-menu'
}
}
],
meta: {
title: '一级菜单',
icon: 'ic:outline-menu'
}
}
],
meta: {
title: '多级菜单',
icon: 'carbon:menu',
order: 7
}
},
{
name: 'about',
path: '/about',
component: 'self',
meta: {
title: '关于',
requiresAuth: true,
singleLayout: 'basic',
permissions: ['super', 'admin', 'user'],
icon: 'fluent:book-information-24-regular',
order: 8
}
}
];
function dataMiddleware(data: AuthRoute.Route[]): ApiRoute.Route {
const routeHomeName: AuthRoute.RouteKey = 'dashboard_analysis';
data.sort((next, pre) => Number(next.meta?.order) - Number(pre.meta?.order));
const filters = filterAuthRoutesByUserPermission(data, 'admin');
return {
routes: filters,
home: routeHomeName
};
}
import { userModel, routeModel } from '../model';
const apis: MockMethod[] = [
{
url: '/mock/getUserRoutes',
method: 'post',
response: (): Service.MockServiceResult => {
response: (options: Service.MockOption): Service.MockServiceResult => {
const { userId = undefined } = options.body;
const routeHomeName: AuthRoute.RouteKey = 'dashboard_analysis';
const role = userModel.find(item => item.userId === userId)?.userRole || 'user';
const filterRoutes = routeModel[role];
return {
code: 200,
message: 'ok',
data: dataMiddleware(routes)
data: {
routes: filterRoutes,
home: routeHomeName
}
};
}
}