一.了解用法

1.了解(session,cookie)token

Token的引入:Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生。

token 是在服务端产生的一串字符串,以作客户端进行请求的一个令牌。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌(除非设置了有效期)。

2.token 优点

Token 完全由应用管理,所以它可以避开同源策略

Token 可以避免 CSRF 攻击

Token 可以是无状态的,可以在多个服务间共享

减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。

1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码

2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token

3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面

4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面

5、每次调后端接口,都要在请求头中加token

6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401

7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面

二.实际使用

1.封装一个本地缓存的方法

在src下新建一个storage文件夹,文件夹里新建index.vue

代码如下:

// 封装操作localstorage本地存储的方法 模块化

var storage = {

set(key, value) {

localStorage.setItem(key, JSON.stringify(value))

},

get(key) {

return localStorage.getItem(key) != 'undefined' ? JSON.parse(localStorage.getItem(key)) : undefined

},

getForIndex(index) {

return localStorage.key(index)

},

getKeys() {

let items = this.getAll()

let keys = []

for (let index = 0; index < items.length; index++) {

keys.push(items[index].key)

}

return keys

},

getLength() {

return localStorage.length

},

getSupport() {

return (typeof (Storage) !== 'undefined')

},

remove(key) {

localStorage.removeItem(key)

},

removeAll() {

localStorage.clear()

},

getAll() {

let len = localStorage.length // 获取长度

let arr = new Array(len) // 定义数据集

for (var i = 0; i < len; i++) {

// 获取key 索引从0开始

var getKey = localStorage.key(i)

// 获取key对应的值

var getVal = localStorage.getItem(getKey)

// 放进数组

arr[i] = {

'key': getKey,

'val': getVal

}

}

return arr

}

}

export default storage

2.封装好storage后,把他挂载到全局组件中

打开src下的main.js

加上一句代码:

Vue.prototype.$storage = storage;

1

3.在request.js里放入token

至于request是什么,具体可以参考另一篇文档:“Vue如何成功调用一个动态数据接口+解决跨域问题”:该文档链接点击跳转

其中的方法二具体描述了request.js

每次跳转路由前,判断 localStroage(或vuex) 中有无 token,或者是否过期(可以写在封装Axios的请求拦截器中或者router的路由守卫中)

request.js代码如下

import axios from 'axios'

import storage from '@/storage'

import router from '@/router'

// create an axios instance

const service = axios.create({

baseURL: '/api', // url = base url + request url

timeout: 5000 // request timeout

})

// 添加请求拦截器,若token存在则在请求头中加token,不存在也继续请求

service.interceptors.request.use(

config => {

// 每次发送请求之前检测都vuex存有token,那么都要放在请求头发送给服务器,没有则不带token

// Authorization是必须的

let tokenInfo = storage.get('TOKEN')

const token = tokenInfo ? tokenInfo.accessToken : null

const tokenType = token ? tokenInfo.tokenType.substring(0, 1).toUpperCase() + tokenInfo.tokenType.substring(1) + ' ' : null

if (token && tokenType) {

config.headers.Authorization = tokenType + token

}

return config

},

error => {

console.log('在request拦截器检查到错误:', error.response)

return Promise.reject(error)

}

)

// respone拦截器

service.interceptors.response.use(

response => {

return response

},

error => {

// 在status不正确的情况下,判别status状态码给出对应响应

if (error.response) {

console.log('在respone拦截器检查到错误:')

switch (error.response.status) {

case 204:

error.response.data.error = '204:No Content(没有内容)'

break

case 401:

// 可能是token过期,清除它

storage.remove('tokenInfo')

location.reload() // 刷新页面,触发路由守卫

error.response.data.error = '401:Unauthorized(未经授权)'

break

case 403:

error.response.data.error = '403:Forbidden(被禁止的)'

break

case 500:

error.response.data.error = '500:服务器内部错误'

break

default:

return error

}

return Promise.reject(error.response.data.error)

}

return Promise.reject(error)

}

)

export default service

4.在路由,router下的index.vue里设置路由守卫

整个index代码如下:

import Vue from 'vue'

import Router from 'vue-router'

import Login from '@/views/login';

import Main from '@/main/index';

import tip1 from '@/views/tip1';

import tip2 from '@/views/tip2';

import tip3 from '@/views/tip3';

import storage from '@/storage'

Vue.use(Router)

const routes = [{

path: '/',

name: 'Login',

// redirect: '/login',

component: Login,

},

{

path: "/login",

component: Login,

},

{

path: '/Main',

component: Main,

children: [{

path: '/',

name: 'Tip1',

component: tip1

},

{

path: '/tip1',

name: 'Tip1',

component: tip1

},

{

path: '/tip2',

name: 'Tip2',

component: tip2,

meta: {

requireAuth: true

}

},

{

path: '/tip3',

name: 'Tip3',

component: tip3

},

]

}

]

const router = new Router({

routes

})

// 设置路由守卫,在进页面之前,判断有token,才进入页面,否则返回登录页面

router.beforeEach((to, from, next) => {

// 默认requiresAuth为false才不需要登录,其他都要

// to.matched.some(r => r.meta.requireAuth) or to.meta.requiresAuth

if (to.matched.some(r => r.meta.requireAuth) !== false) {

let tokenInfo = storage.get('TOKEN')

if (tokenInfo) {

console.log("有token")

next();

} else {

storage.remove('TOKEN')

next({

path: "/login",

query: {

redirect: to.fullPath

} // 将刚刚要去的路由path(却无权限)作为参数,方便登录成功后直接跳转到该路由

});

}

} else {

next(); //如果无需token,那么随它去吧

}

});

//暴露router实例

export default router

// 1.将调用登录接口成功以后,把后端传过来的token放入本地缓存

// 2.路由跳转之前执行路由守卫,实例化一个Router对象,使用该对象内置方法beforeEach,在路由跳转前判断该页面是否设置了token,获取token

// 如果有token,next()继续执行路由跳转

// 如果没有token,跳转去登录界面

哪个页面需要路由守卫。就给他加上参数

meta: {

requireAuth: true

}

转载、文章来源:https://blog.csdn.net/weixin_46166949/article/details/105856745

Logo

前往低代码交流专区

更多推荐