在用vue开发过程中,经常会遇到这种需求,有些组件是需要登录之后才能够去访问,有些组件是任何用户都能够访问,我们可以通过前端路由拦截+http拦截来达成这种目的(假定以token来验证)。
技术栈:
- vue2.0
- vue-router
- axios
目录结构:
前端路由拦截
路由配置如下,在这里自定义了一个元数据meta: {authRequired: true}来标记哪些路由是需要登录验证的,导航被触发的时候只要判断是否目标路由中是否有meta这个对象,且meta包含authRequired属性,其值为true。这里访问/user/userinfo是需要登录拦截的。
const router = new Router({
routes: [
{
path: '/',
redirect: '/homepage',
},
{
path: '/login',
component: LogIn
},
{
path: '/homepage',
component: HomePage,
children: [
{
path: 'userinfo',
component: UserInfo,
meta: {authRequired: true}
},
{
path: 'news',
component: News,
}
]
}
]
})
通过router.beforeEach注册一个全局前置守卫来进行判断拦截,每一次导航被触发时都会调用这个全局守卫。
router.beforeEach((to, from, next) => {
//判断是否需要登录拦截
if(to.meta.authRequired) {
//存在token正常跳转
if(localStorage.getItem('token')) {
next()
} else {
next({path: '/login', query:{redirect: to.fullPath}})
}
} else {
next()
}
})
next({path: '/login', query:{redirect: to.fullPath}})
//在触发/login路由时,会携带额外的参数,相当于/login?redirect=to.fullPath,目的是在登录完成之后可以返回到当前页面。
对于嵌套路由,做好使用如下代码判断,当你访问一个子路由时,会同时匹配到当前路由和父路由。
请参考https://router.vuejs.org/zh/guide/advanced/meta.html
if(to.matched.some(record => {record.meta.authRequired})) {//....}
http拦截
vue-resource在vue2.0之后已不再维护,推荐使用axios http库。
这里需要对每个request都绑定上token,对每个response都需要验证其状态。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
config.headers['Authorization'] = localStorage.getItem('token');
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
// 当验证不通过,则清除本地保存的token,并且返回登录界面
if(error.status === 401) {
localStorage.removeItem('token');
this.$router.push('/login');
}
return Promise.reject(error);
});
后端代码
后端:python2.7 + webpy
需要安装webpy和pyjwt。
index.py
# -*- coding:utf-8 -*-
import web
import time
import jwt
import json
url = (
'/login', 'Login',
'/userinfo', 'UserInfo'
)
USER = 'admin'
PASSWORD = '123456'
app = web.application(url, globals())
def create_token():
payload = {
"iat": int(time.time()),
"exp": int(time.time()) + 86400 * 7,
"scopes": ['open']
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
return {'token': token}
def verify_bearer_token(token):
try:
payload = jwt.decode(token, 'secret', algorithms=['HS256'])
except Exception, e:
print e
return False
else:
if payload:
return True
else:
return False
class Login(object):
def POST(self):
data = eval(web.data())
try:
if data['usr'] == USER and data['psd'] == PASSWORD:
token = create_token()
return json.dumps(token)
except Exception, e:
print e
web.ctx.status = '401'
return json.dumps({'status': 'fail'})
class UserInfo(object):
def GET(self):
if 'HTTP_Authorization'.upper() in web.ctx.env:
token = web.ctx.env['HTTP_Authorization'.upper()]
if token and verify_bearer_token(token):
return json.dumps({'firstname': 'ab', 'lastname': 'cd'})
web.ctx.status = '401'
return json.dumps({'status': 'fail'})
if __name__ == '__main__':
app.run()
运行:
先运行python2.7 index.py 80,然后在vue项目的根目录执行npm run dev,在浏览器输入127.0.0.1:8080即可查看demo。
github地址:https://github.com/shanjianfei/vue_intercept