vue与jwt验证
简介:本文讲解,如何使用vue,对jwt进行验证。
后端部分看这篇文章:SpringBoot+JWT+Shiro
这篇文章的代码可以在这里下载:jwt项目演示
数据库设计
前端代码
我前段所采取vue2+element-ui
项目结构
main.js
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.config.productionTip = false Vue.use(ElementUI); new Vue({ router, store, render: h => h(App) }).$mount('#app')
App.vue
<template> <div id="app"> <router-view/> </div> </template> <style lang="scss"> </style>
index.js
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const routes = [ { path: '/', name: 'login', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/login/LoginView.vue') }, { path: '/register', name: 'register', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/register/RegisterView.vue') }, { path: '/index', name: 'index', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/index/IndexView.vue') } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router
store
index.js
import Vue from 'vue' import Vuex from 'vuex' import auth from './auth' Vue.use(Vuex) export default new Vuex.Store({ modules: { auth: { namespaced: true, // 添加命名空间 ...auth } } })
auth.js
// auth.js import axios from 'axios'; import router from '@/router'; const auth = { state: { token: null }, mutations: { SET_TOKEN(state, token) { state.token = token; }, CLEAR_TOKEN(state) { state.token = null; } }, actions: { login({ commit }, loginForm) { return new Promise((resolve, reject) => { // 调用登录接口,传递登录表单数据 axios.post('http://localhost:8989/user/login', loginForm) .then(response => { const token = response.data.data.token; // 将token保存到Vuex中 commit('SET_TOKEN', token); // 将token保存到浏览器的localStorage中,以便在刷新页面后仍然可以保持登录状态 localStorage.setItem('token', token); resolve(); }) .catch(error => { reject(error); }); }); }, logout({ commit }) { // 清除token并重定向到登录页面 commit('CLEAR_TOKEN'); localStorage.removeItem('token'); router.push('/'); }, checkToken({ commit }) { const token = localStorage.getItem('token'); if (token) { // 将token保存到Vuex中 commit('SET_TOKEN', token); } else { // 如果没有token,则重定向到登录页面 router.push('/'); } }, }, getters: { getToken(state){ console.log("我被调用了") return state.token; } } }; export default auth;
LoginView.vue
<template> <div class="login-container" style="display: flex; justify-content: center; align-items: center;"> <el-card class="login-card"> <h2 class="login-title">登录</h2> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-width="80px" class="login-form"> <el-form-item label="用户名" prop="username"> <el-input v-model="loginForm.username" placeholder="请输入用户名"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="loginForm.password" placeholder="请输入密码"></el-input> </el-form-item> <el-form-item> <div style="padding-left: 10%;"> <el-button type="primary" @click="Login">登录</el-button> <span style="padding-left: 10%;"> <el-link type="primary" @click="Register">注册</el-link> </span> </div> </el-form-item> </el-form> </el-card> </div> </template> <script> import {mapActions } from 'vuex'; export default { data() { return { loginForm: { username: 'lihua2', password: '123456' }, loginRules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ] } }; }, methods: { ...mapActions('auth', ['login']), Login() { // 验证表单 this.$refs.loginForm.validate(valid => { console.log("表单验证成功") if (valid) { // 调用 auth 模块中的 login action this.login(this.loginForm) .then(() => { // 重定向到首页或其他页面 this.$router.push('/index'); }) .catch(error => { console.log('登录失败:', error); }); } else { console.log('表单验证失败'); } }); }, Register() { this.$router.push('/register'); } } }; </script> <style scoped> .login-container { display: flex; justify-content: center; align-items: center; height: 100vh; } .login-card { width: 400px; padding: 20px; } .login-title { text-align: center; margin-bottom: 20px; } .login-form { margin-top: 20px; } </style>
IndexView.html
<template> <div> <el-button type="primary" @click="loginOut">退出</el-button> <el-table :data="users" style="width: 100%"> <el-table-column prop="id" label="ID"></el-table-column> <el-table-column prop="username" label="Name"></el-table-column> <!-- 其他列... --> </el-table> </div> </template> <script> import { mapActions, mapGetters } from 'vuex'; import axios from 'axios'; export default { data() { return { users: [], }; }, computed:{ ...mapGetters('auth', ['getToken']), ...mapActions('auth', ['logout']) }, mounted() { this.getAll(); }, methods: { getAll() { const token = this.getToken; console.log(token) axios.get(`http://localhost:8989/user/all/${token}`) .then(response => { this.users = response.data.data.data; }) .catch(error => { console.error(error); }); }, loginOut(){ this.logout() this.$router.push("/") } }, }; </script>
Register.vue
<template> <div class="register-container" style="display: flex; justify-content: center; align-items: center;"> <el-card class="register-card"> <h2 class="register-title">注册</h2> <el-form ref="registerForm" :model="registerForm" :rules="registerRules" label-width="80px" class="register-form"> <el-form-item label="用户名" prop="username"> <el-input v-model="registerForm.username" placeholder="请输入用户名"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="registerForm.password" placeholder="请输入密码"></el-input> </el-form-item> <el-form-item label="确认密码" prop="confirmPassword"> <el-input type="password" v-model="registerForm.confirmPassword" placeholder="请再次输入密码"></el-input> </el-form-item> <el-form-item> <div style="padding-left: 10%;"> <el-button type="primary" @click="Register">注册</el-button> <span style="padding-left: 10%;"> <el-link type="primary" @click="Login">登录</el-link> </span> </div> </el-form-item> </el-form> </el-card> </div> </template> <script> import axios from 'axios'; export default { data() { return { registerForm: { username: '', password: '', confirmPassword: '' }, registerRules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ], confirmPassword: [ { required: true, message: '请再次输入密码', trigger: 'blur' }, { validator: this.validateConfirmPassword, trigger: 'blur' } ] } }; }, methods: { Register() { const formData = { username: this.registerForm.username, password: this.registerForm.password } this.$refs.registerForm.validate((valid) => { if (valid) { axios.post("http://localhost:8989/user/register", formData) .then(response => { if (response.data.code == 200){ console.log("注册成功") alert("注册成功,现在返回登录页面>_<") this.$router.push("/") } else { alert(response.data.message) } }) } else { console.log('Invalid registration form'); } }); }, validateConfirmPassword(rule, value, callback) { if (value !== this.registerForm.password) { callback(new Error('两次输入的密码不一致')); } else { callback(); } }, Login() { this.$router.push("/") } } }; </script> <style scoped> .register-container { display: flex; justify-content: center; align-items: center; height: 100vh; } .register-card { width: 400px; padding: 20px; } .register-title { text-align: center; font-size: 24px; margin-bottom: 20px; } .register-form { margin-top: 20px; } </style>