具体步骤:
- 首次登录,将用户名密码传给后端,返回
token。 - 将
token存储在localStroage和Vuex中。 - 用
Axios将token写入请求头中。 - 前端每次请求接口都将携带
token信息。 - 后端判断
token是否过期,过期或者没有,则返回401。 - 前端根据401状态码,将页面重定向到登录页面中。
封装LocalStorage
const TokenKey = 'packet_token'
export function getToken() {
return localStorage.getItem(TokenKey)
}
export function setToken(token) {
return localStorage.setItem(TokenKey, token)
}
export function removeToken() {
return localStorage.removeItem(TokenKey)
}
封装非常简单,封装三个方法getToken、setToken、removeToken。
- 登录时,调用setToken将token值存储到localStorage中
- 请求接口时,调用getToken将token值放在请求头中。
- token过期时,调用removeToken将localStorage中的token移除。
封装Axios
然后配置请求拦截器,目的是为了将每个请求都写入一个packet_token 的header。
server.interceptors.request.use(request => {
request.headers['packet_token'] = getToken()
return request
}, error => {
return Promise.reject(error)
})
接着配置响应拦截器,目的是拦截401状态码。
如果出现401状态码,就调用removeToken删除localStorage中的token并刷新页面。
server.interceptors.response.use(response => {
return response
}, error => {
if (error.response.status === 401) {
removeToken()
location.reload()
}
return Promise.reject(error)
})
路由处理
访问登录之外的页面,都需要登录权限。比如首页,判断是否存在token,有就访问成功,没有则跳转到登录页面。
页面路由跳转过程中,会使用全局钩子router.beforeEach中拦截路由,检测到没有token就重定向至登录页面。
router.beforeEach((to, from, next) => {
if (localStorage.getItem('packet_token') === null && to.path !== '/login') {
next({ path: '/login' })
}
next()
})
大致上,登录功能就已经完成了。
权限
有登录必有权限,有些页面只有管理员才能访问,有些页面所有人都能访问。那怎么处理比较好呢?
路由级别的权限,我建议前端自己来配置,要不然,在开发阶段,每增加一个路由就要后端去配置,简直是噩梦。
具体实现:
- 在挂载router时,先将一些公用页面挂载,比如说登录页面。
- 当用户登录后,获取到用户角色的权限,再将其权限与路由表中每个页面所需的权限作一次比较,生成用户最终的路由表。
- 调用router.addRouter()方法将其路由表添加到vue-router中。
// router.js
export const normalRoutes = [
{
path: '/login',
name: 'login'
component: Login
},
{
path: '/',
name: '首页'
component: Index
}
]
export const asyncRouters = [
{
path: '/edit',
name: '编辑页面',
component: Edit,
role: {
role: ['admin, 'editor']
}
},
...
{
path: '*',
redirect: '/404'
}
]
注意:404页面一定要最后加载,如果放在normalRoutes中,后面的路由访问都将会被拦截到404。
router.beforeEach((to, from, next) => {
if (localStorage.getItem('packet_token') === null && to.path !== '/login') {
next({ path: '/login' })
} else {
// 请求用户权限信息
// 生成可访问的路由表
next();
}
next()
})