vuejs用户认证实例

Posted on 2017-11-30 |    

在本例子中,使用的请求方法都是使用axios,vuejs的官方推荐。

安装与使用axios

1
npm install axios

在main.js(如果你使用的是vue-cli脚手架搭建的项目)中引入

1
2
import axios from 'axios'
Vue.prototype.$http = axios

之后使用小栗子即是

1
2
3
4
5
this.$http.get(URL).then(response => {
// success callback
}, response => {
// error callback
})

登录

在登录部分,登录成功后,将服务器返回的token存在sessionstorage中,当然也可以放在localstorage,或者使用vuex的方式存储token数据和用户信息。

1
2
3
4
5
6
7
8
9
10
11
12
var url = "/api/web/login";
var data={username:this.username,password:this.password};
this.$http({method:"get",url:url,auth:data}).then(response => {
if(response.status==200){
// this.$store.state.token=response.data.token;
sessionStorage.token = response.data.token;
sessionStorage.username = response.data.username;
this.$router.push(this.$route.query.redirect||'/'); //登录成功则跳转到首页
}
}).catch(function(error){
//error
});

路由配置

以前写路由配置的时候即只是如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from 'vue'
import Router from 'vue-router'
import Web from '@/components/Web'
import Dashboard from '@/components/Dashboard'

Vue.use(Router)

export default new Router({
routes: [
{
path: '/',
name: 'Web',
component: Web,
children:[
{
path: "/", name: 'Dashboard', component: Dashboard
}
]
}
]
})

当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。这就是懒加载。
改成如下的方式即可实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import Vue from 'vue'
import Router from 'vue-router'


Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'Web',
component(resolve) {
require.ensure(['@/components/Web.vue'], () => {
resolve(require('@/components/Web.vue'));
});
},
meta: {
requireAuth: true
},
children:[
{
path:"/",
name:'Dashboard',
component(resolve) {
require.ensure(['@/components/Dashboard.vue'], () => {
resolve(require('@/components/Dashboard.vue'));
});
},
meta: {
requireAuth: true
}
},
{
path:'/login',
name:'Login',
component(resolve) {
require.ensure(['@/components/Login.vue'], () => {
resolve(require('@/components/Login.vue'));
});
},
}
]
})

同时,还加入了路由元信息,配置了meta-requireAuth字段,来判断在这个路由中是否需要身份认证
利用"导航守卫“来检查该字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
router.beforeEach((to, from, next) => {
let token = sessionStorage.token;//从sessionstorage中获取,或者利用localstorage和vuex
if(to.meta.requireAuth) { //如果该路由需要登录
if(token) { //且token是存在的,则可以进入该路由
next()
} else {
next({
path: '/login', //否则跳转到登录页面,
query: { redirect: to.fullPath }//将跳转的路由path作为参数,登录成功后跳转到该路由
})
}
} else {
next()
}
})

export default router

[tip:]

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    1. next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    2. next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    3. next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
    4. next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

axios拦截器

在做了以上情况之后,你只是做到了表面上的前端路由控制,接下来我们使用axios拦截器实现以下功能:
1.登陆后,为了保持认证的请求,在每次请求的头部加上登录成功时返回的token信息
2.发送不合法的请求或者在没有认证的情况下发送请求后,如果服务器返回的状态是401(Unauthorized 未授权)或者403(Forbidden 拒绝),则跳转到登录页面。

发起每次请求时,都在头部加上token字段,让服务器验证token是否有效,如果后端接口返回 401 或者403 ,则让用户重新登录,并清除token信息。

1
2
3
4
5
6
7
8
9
10
11
axios.interceptors.request.use(
config=>{
if(sessionStorage.token){
config.auth = {username:sessionStorage.token,password:""};
}
return config;
},
err=>{
return Promise.reject(err);
}
);

在这里,我是将token信息作为username,password置为空,赋予axios的auth字段,这样会直接进行base64编码作为基础认证传给服务器。
当然也可以使用以下方式将token赋予请求头部的Authorization字段返回给服务器。

1
config.headers.Authorization = `token ${sessionStoreage.token}`;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
axios.interceptors.response.use(
response => {
return response;
},
error => {
if (error.response) {
switch (error.response.status) {
case 401:
// 返回 401 清除token信息并跳转到登录页面
sessionStorage.token="";
router.replace({
path: '/login',
query: {redirect: router.currentRoute.fullPath}
});
break;
case 403:
// 返回 401 清除token信息并跳转到登录页面
sessionStorage.token="";
router.replace({
path: '/login',
query: {redirect: router.currentRoute.fullPath}
})
break;
}
}
return Promise.reject(error.response.data) // 返回接口返回的错误信息
}
);

至此,整个用户认证实例即结束。
登出的时候,只要将保存在storage里的token和用户信息清除,跳转到登录页或者不需认证的首页即可。

参考:
https://router.vuejs.org/zh-cn/advanced/navigation-guards.html