📢注意:
- 暂未找到路由全局拦截配置(就是vue-router的路由守卫,解决方案:(无权限,或账号密码错误,或路由错误等)与后端约定,根据报错的状态码,跳到对应报错页面)
- icestark路由跳转必须使用appHistory!
- 不细说:配置代理就build.json配置proxy、请求用ice里封装好的request
- Token里存的用户角色
👦思路:
- 第一次登录页时,先移除Token(不管有没有),用账号密码发送请求,请求成功跳回主页面,并存储Token
- 第二次打开页面,如果有Token
- 有Token,验证是否过期(发checkToken请求)
- 过期跳转Login登录页
- 没有过期则允许进入(就不做多余操作)
- 没有Token,直接跳转Login登录页
- 路由每次跳转时,验证是否过期(发checkToken请求)
☀️关键:业务上封装统一的请求方法,与服务端约定接口协议,前端根据状态码判断无权限、未登录等状态,然后跳转到指定页面
一.配置全局请求拦截
思路 1 、请求拦截:
-
如果有token,携带token发请求。
-
如果没有token,排除主路由外的分组路由(比如忘记密码路由是不用刷新跳回登录页的,但是主页里面的路由刷新如果没有权限需要跳回登录页)之后跳回登录页。
思路 2 、响应拦截:
- 如果成功,提示成功。
思路 3 、错误拦截:
- 与后端约定,根据不同status,对应不同权限,渲染不同组件
request: {
withFullResponse: false,//全局设置 request 是否返回 response 对象,默认为 false-----截取响应数据
interceptors: {//拦截
request: {//全局拦截请求
onConfig: (config) => {
const accessToken = localStorage.getItem('ACCESS_TOKEN');
if (accessToken) {
config.headers = { Authorization: `Bearer ${accessToken}` } //每次请求携带Token
} else if (location.pathname !== '/login' && location.pathname !== '/register' && location.pathname !== '/forgotpassword') {//分组路由限制
appHistory.push('/login');
}
return config;
}
},
response: {//全局拦截响应
onConfig: (response: any) => {
const success = response.data.success ? response.data.success : response.data.message === '成功';//还需了解
if (!success) {
// 提示失败信息
const { data: { msg } } = response;//连续解构赋值
Message.error(msg);
return Promise.reject(msg);
}
return response.data;
},
onError: (error: any) => {//全局拦截请求报错
// 业务上封装统一的请求方法,与服务端约定接口协议,前端根据状态码判断无权限、未登录等状态,然后跳转到指定页面。!!!!!!!!!!
const status = error.response.status;
console.log(status);
if (status === 401) {
const accessToken = localStorage.getItem('ACCESS_TOKEN');
if (accessToken) Message.error("用户身份信息已失效,请重新登录")
appHistory.push('/login');// 跳转到登录页面,重新登录(账号密码输入错误的时候)
} else if (status === 403) {
appHistory.push('/feedback/403');// 跳转到没有权限页面
} else if (status === 404) {
appHistory.push('/feedback/404');// not found页面
} else {
appHistory.replace('/login');
}
return Promise.reject(error);
}
},
}
},
二、路由级权限配置
路由级(页面级)权限,按钮级权限🎈颗粒度到按钮(后端返回权限数组,判断当前按钮权限字段能否匹配)
-
路由级别路由配置使用高阶组件,有app.tsx里的auth判断是否有当前页面权限,没有则不显示(先暂时跳转login)
-
目的:配置下面三个就可控制路由级别权限
- app.tsx配置getInitialData初始化的时候获取权限
getInitialData: async () => { // 业务上封装统一的请求方法,与服务端约定接口协议,前端根据状态码判断无权限、未登录等状态,然后跳转到指定页面。!!!!!!!!!! try { const data = await request('/user/permission');// 发请求拿权限或者验证权限 return { auth: data } } catch (e) { return { auth: {} } } }, auth: { NoAuthFallback: <FeedbackForbidden />,//设置无权限时的展示组件默认为 null // 或者传递一个函数组件:NoAuthFallback: () => <div>没有权限..</div> }, //外层的router也需要配菊花!!! router: { type: 'browser',// 统一History路由 fallback: <PageLoading /> },
- 高阶组件:
//路由高阶组件 import { useAuth, Redirect } from 'ice'; const LoginWrapper = (WrappedComponent) => { const Wrapped = (props) => { const [auth] = useAuth(); console.log(auth,"取到的页面配置auth"); return <>{auth.isLogin ? <WrappedComponent {...props} /> : <Redirect to="/login" />}</>; }; return Wrapped; }; export default LoginWrapper;
- 🧡路由匹配高阶组件、这个地方记得组件懒加载(暂时没写报错的路由跳转):
import { IRouterConfig, lazy } from 'ice'; import Home from '@/pages/Home'; import Login from '@/pages/Login'; import NotFound from '@/components/NotFound'; import wrapperPage from '@/components/LoginWrapper' const Register = lazy(() => import('@/pages/Register')); const ForgotPassword = lazy(() => import('@/pages/ForgotPassword/components/StepForm')); const Instruction = lazy(() => import('@/pages/Instruction')); const routes: IRouterConfig[] = [ //新的分组路由需要到 layout里的FrameworkLayout、app.tsx里的request 改判断 { path: '/login',//登录 component: Login, }, { path: '/register',//注册 component: Register, }, { path: '/forgotpassword',//忘记密码 component: ForgotPassword, }, { path: '/instruction',//账号说明 component: Instruction, }, { path: '/',//主应用==首页 exact: true,//精准匹配 component: Home, wrappers: [wrapperPage], }, { component: NotFound, } ]; export default routes;
三、按钮级权限配置
正在开发中。。。🤣🤣🤣
四、UI图还没出、原型还没定、配得也差不多了、先写一波页面
进度:
- 搭好了主应用、微应用
- Token管理、请求拦截、代理、表单收集
- 路由级权限、菜单配置
下一步:
- 颗粒度做到按钮
- 请求url尝试封装到一起
- 面包屑导航
- 简单响应式优化