loginVO.setId(uer.getId());
//这里token直接用一个uuid
//使用jwt的情况下,会生成一个jwt token,jwt token里会包含用户的信息
loginVO.setToken(UUID.randomUUID().toString());
loginVO.setUser(uer);
return new Result(200,“”,loginVO);
}
return new Result(401,“登录失败”,“”);
}
}
其中对返回的data
封装了一个VO:
/**
-
@Author: 三分恶
-
@Date: 2021/1/18
-
@Description: 登录VO
**/
public class LoginVO implements Serializable {
private Integer id;
private String token;
private User user;
//省略getter、setter
}
最后,测试一下登录接口:
OK,没有问题。
前面我们使用了后端拦截器,接下来我们尝试用前端实现相似的功能。
实现前端登录器,需要在前端判断用户的登录状态。我们可以像之前那样在组件的 data 中设置一个状态标志,但登录状态应该被视为一个全局属性,而不应该只写在某一组件中。所以我们需要引入一个新的工具——Vuex,它是专门为 Vue 开发的状态管理方案,我们可以把需要在各个组件中传递使用的变量、方法定义在这里。
2.1引入Vuex
首先在终端里使用命令 npm install vuex --save
来安装 Vuex 。
在 src 目录下新建一个文件夹 store,并在该目录下新建 index.js 文件,在该文件中引入 vue 和 vuex,代码如下:
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
接下来,在index.js
里设置我们需要的状态变量和方法。为了实现登录拦截器,我们需要一个记录token的变量量。同时为了全局使用用户信息,我们还需要一个记录用户信息的变量。还需要改变变量值的mutations。完整的代码如下:
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token: sessionStorage.getItem(“token”),
user: JSON.parse(sessionStorage.getItem(“user”))
},
mutations: {
// set
SET_TOKENN: (state, token) => {
state.token = token
sessionStorage.setItem(“token”, token)
},
SET_USER: (state, user) => {
state.user = user
sessionStorage.setItem(“user”, JSON.stringify(user))
},
REMOVE_INFO : (state) => {
state.token = ‘’
state.user = {}
sessionStorage.setItem(“token”, ‘’)
sessionStorage.setItem(“user”, JSON.stringify(‘’))
}
},
getters: {
},
actions: {
},
modules: {
}
})
这里我们还用到了 sessionStorage
,使用sessionStorage
,关掉浏览器的时候会被清除掉,和 localStorage
相比,比较利于保证实时性。
2.2、修改路由配置
为了能够区分哪些路由需要被拦截,我们在路由里添上一个元数据requireAuth
来做是否需要拦截的判断:
{
path: ‘/’,
name: ‘HelloWorld’,
component: HelloWorld,
meta: {
requireAuth: true
}
},
完整的 src\router\index.js
代码如下:
import Vue from ‘vue’
import Router from ‘vue-router’
import HelloWorld from ‘@/components/HelloWorld’
//导入登录页面组件
import Login from ‘@/views/login.vue’
Vue.use(Router)
export default new Router({
routes: [
{
path: ‘/’,
name: ‘HelloWorld’,
component: HelloWorld,
meta: {
requireAuth: true
}
},
//添加登录页面路由
{
path:‘/login’,
name: ‘Login’,
component: Login
}
]
})
2.3、使用钩子函数判断是否拦截
上面我们添加了 requireAuth
, 接下来就要用到它了。
钩子函数及在某些时机会被调用的函数。这里我们使用 router.beforeEach()
,意思是在访问每一个路由前调用。
打开 src\main.js
,首先添加对 store
的引用
import store from ‘./store’
并修改vue对象里的内容,使 store 能全局使用:
new Vue({
el: ‘#app’,
router,
// 注意这里
store,
components: { App },
template: ‘’
})
解下来,我们写beforeEach()
函数,逻辑很简单,判断是否需要登录,如果是,判断 store中是否存有token ,是则放行,否则跳转到登录页。
//钩子函数,访问路由前调用
router.beforeEach((to, from, next) => {
//路由需要认证
if (to.meta.requireAuth) {
//判断store里是否有token
if (store.state.token) {
next()
} else {
next({
path: ‘login’,
query: { redirect: to.fullPath }
})
}
} else {
next()
}
}
)
完整的 main.js 代码如下:
// The Vue build version to load with the import
command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from ‘vue’
import App from ‘./App’
import router from ‘./router’
//引入ElementUI
import ElementUI from ‘element-ui’
import ‘element-ui/lib/theme-chalk/index.css’
import store from ‘./store’
var axios = require(‘axios’)
// 全局注册,之后可在其他组件中通过 this.$axios 发送数据
Vue.prototype.$axios = axios
// 设置反向代理,前端请求默认发送到 http://localhost:8888/api
axios.defaults.baseURL = ‘http://localhost:8088/api’
Vue.config.productionTip = false
/* eslint-disable no-new */
Vue.use(ElementUI)
//钩子函数,访问路由前调用
router.beforeEach((to, from, next) => {
//路由需要认证
if (to.meta.requireAuth) {
//判断store里是否有token
if (store.state.token) {
next()
} else {
next({
path: ‘login’,
query: { redirect: to.fullPath }
})
}
} else {
next()
}
}
)
new Vue({
el: ‘#app’,
router,
// 注意这里
store,
components: { App },
template: ‘’
})
2.4、请求封装
我们前面写的后端拦截器,对请求进行了拦截,要求请求头里携带token,这个怎么处理呢?
答案是封装axios
。
在 src 目录下新建目录 utils ,在uitls 目录下新建文件 request.js 。
首先导入 axios
和 store
:
import axios from ‘axios’
import store from ‘@/store’
接下来在请求拦截器中,给请求头添加 token
:
// request 请求拦截
service.interceptors.request.use(
config => {
if (store.state.token) {
config.headers[‘token’] = window.sessionStorage.getItem(“token”)
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
完整的request.js:
import axios from ‘axios’
import store from ‘@/store’
//const baseURL=“localhost:8088/api”
//创建axios实例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
})
// request 请求拦截
service.interceptors.request.use(
config => {
if (store.getters.getToken) {
config.headers[‘token’] = window.sessionStorage.getItem(“token”)
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
//re