前言
因为业务性质原因,之前的项目,其实没有做账号管理,默认登录。
最近要求做账号权限管理,所以需要在api请求中验证token。
前端逻辑
- 登录的时候后端返回一个token。
- 登陆成功,token写入sessionStorage/localStorage。
- vuex存储token。
- axios拦截请求,请求头判断token是否存在,如果存在,设置自定义字段
config.headers.Token = token
- axios拦截响应,获取HTTP状态,如果状态为401,即未登录/登陆过期,情况本地相关token信息,跳转到登录页。
- 其他设置
Content-Type
、数据格式化 - 跨域相关设置
withCredentials
、crossDomain
后端逻辑
- 设置支持自定义字段token。
Access-Control-Allow-Headers:x-requested-with,content-type,token
- 拦截OPTIONS请求,返回200。如果跨域,需要设置跨域允许,否则前端不能正确得到OPTIONS结果。
- 对于GET/POST请求,检测请求头中的token字段,校验结果决定是否走下一步流程。
- 如果校验通过,走正常的业务逻辑。否则,设置HTTP状态为401,中断业务流程,返回校验结果。
问题
解决过程中,容易出现以下问题:
- 前端拦截请求的时候,设置自定义字段,首字母大小写。必须大写。
- 后端处理OPTIONS请求的时候,不能正确设置允许跨域,导致前端不能正确得到OPTIONS请求结果,GET/POST请求没有发出。
结语
问题总是解决不完的,每解决完一个问题,都是一次收获!
附上前端js代码:
//设置post的默认格式为form-data
//请求拦截:如果存在token,则把token带在请求头上发送出去
axios.defaults.withCredentials = true;
axios.defaults.crossDomain = true;
axios.interceptors.request.use((config) => {
config.headers = {'Content-Type':'application/x-www-form-urlencoded'}
let token = store.state.token;
if (token) {
config.headers.Token = token;
}
config.data = qs.stringify(config.data, {arrayFormat: 'brackets'});
return config;
});
//响应拦截:如果htpp状态401,则是需要登录,清除token,跳转到登录页
axios.interceptors.response.use(res =>{
return res
}, error => {
if(error.response && error.response.status === 401){
store.commit('clearToken')
router.replace({
path: '/login',
})
}
return Promise.reject(error.response ? error.response.data : error)
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。