路由鉴权功能是Vue+vue-router框架中常见的功能之一,也是前端安全性的一个重要方面。这里提供一个基于Vue+vue-router的路由鉴权实战
安装依赖
首先,在Vue项目中安装所需的依赖。安装Vue、vue-router以及axios等依赖,创建一个新的Vue实例。
npm install vue vue-router axios --save
设置路由和路由守卫
在路由设置中,我们将路由拆分为两类,需要进行鉴权的路由和不需要进行鉴权的路由。需要进行鉴权的路由需要在路由元信息中添加requiresAuth: true属性。
在我们设置路由时,需要引入路由守卫。这里我们使用router.beforeEach守卫,在进入每个路由之前进行鉴权验证。
// main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
Vue.config.productionTip = false;
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) { // 判断该路由是否需要进行鉴权
// 获取token
const token = localStorage.getItem('token');
if (!token) { // token不存在,则跳转到登录页
next('/login');
} else { // token存在,则进行下一步路由
next();
}
} else {
next(); // 不需要进行鉴权,直接进行下一步路由
}
});
new Vue({
router,
render: h => h(App),
}).$mount('#app');
实现登录页
登录页中需要对用户的信息进行验证,并在验证通过后获取返回的token。这里我们使用axios库来发送登录请求。
<template>
<div class="login-page">
<h2>Login</h2>
<div>
<label>Username:</label>
<input type="text" v-model="username">
</div>
<div>
<label>Password:</label>
<input type="password" v-model="password">
</div>
<button @click="login">Login</button>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
password: '',
};
},
methods: {
async login() {
const { data } = await axios.post('/api/login', { username: this.username, password: this.password });
localStorage.setItem('token', data.token); // 将token存入localStorage中
this.$router.push('/');
},
},
};
</script>
<style scoped>
.login-page {
width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #f8f8f8;
border: 1px solid #ccc;
}
input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 10px;
}
button {
padding: 10px 20px;
background-color: #007aff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
设置需要鉴权的路由
在路由设置中,我们为需要鉴权的路由添加requiresAuth元信息。这里我们设定/profile路由需要进行权限验证。
// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './views/Home.vue';
import Login from './views/Login.vue';
import Profile from './views/Profile.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/login',
name: 'login',
component: Login,
},
{
path: '/profile',
name: 'profile',
component: Profile,
meta: {
requiresAuth: true,
},
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
export default router;
实现需要鉴权的页面
最后,在需要鉴权的页面中,我们可以使用beforeRouteEnter守卫来在进入页面前获取用户信息。这里我们使用axios库获取用户信息。
<template>
<div class="profile-page">
<h2>Profile</h2>
<div>
<label>Username:</label>
<span>{{ username }}</span>
</div>
<div>
<label>Email:</label>
<span>{{ email }}</span>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
email: '',
};
},
beforeRouteEnter(to, from, next) {
axios.get('/api/userinfo').then(({ data }) => {
next(vm => {
vm.username = data.username;
vm.email = data.email;
});
}).catch(() => {
next('/');
});
},
};
</script>
<style scoped>
.profile-page {
width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #f8f8f8;
border: 1px solid #ccc;
}
label {
font-weight: bold;
}
span {
margin-left: 10px;
}
</style>
上述代码中,在进入页面之前,我们使用axios发送请求获取用户信息。如果获取失败,则跳转到首页。如果请求成功,则将用户信息存入Vue实例中,并使用next将其传递给组件。在组件中,我们可以直接使用username和email属性渲染页面。
完整的代码如下:
// main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
Vue.config.productionTip = false;
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) { // 判断该路由是否需要进行鉴权
// 获取token
const token = localStorage.getItem('token');
if (!token) { // token不存在,则跳转到登录页
next('/login');
} else { // token存在,则进行下一步路由
next();
}
} else {
next(); // 不需要进行鉴权,直接进行下一步路由
}
});
new Vue({
router,
render: h => h(App),
}).$mount('#app');
// router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './views/Home.vue';
import Login from './views/Login.vue';
import Profile from './views/Profile.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/login',
name: 'login',
component: Login,
},
{
path: '/profile',
name: 'profile',
component: Profile,
meta: {
requiresAuth: true,
},
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
export default router;
// Login.vue
<template>
<div class="login-page">
<h2>Login</h2>
<div>
<label>Username:</label>
<input type="text" v-model="username">
</div>
<div>
<label>Password:</label>
<input type="password" v-model="password">
</div>
<button @click="login">Login</button>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
password: '',
};
},
methods: {
async login() {
const { data } = await axios.post('/api/login', { username: this.username, password: this.password });
localStorage.setItem('token', data.token); // 将token存入localStorage中
this.$router.push('/');
},
},
};
</script>
<style scoped>
.login-page {
width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #f8f8f8;
border: 1px solid #ccc;
}
input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 10px;
}
button {
padding: 10px 20px;
background-color: #007aff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
// Profile.vue
<template>
<div class="profile-page">
<h2>Profile</h2>
<div>
<label>Username:</label>
<span>{{ username }}</span>
</div>
<div>
<label>Email:</label>
<span>{{ email }}</span>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
email: '',
};
},
beforeRouteEnter(to, from, next) {
axios.get('/api/userinfo').then(({ data }) => {
next(vm => {
vm.username = data.username;
vm.email = data.email;
});
}).catch(() => {
next('/');
});
},
};
</script>
<style scoped>
.profile-page {
width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #f8f8f8;
border: 1px solid #ccc;
}
label {
font-weight: bold;
}
span {
margin-left: 10px;
}
</style>