本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1、登录?
1. 前端携带用户名,请求密码,验证码发送请求
- 后端验证密码与数据库中是否相同,相同的话登录成功
登陆成功前发送的cookie,token:
2. 登录成功,后端返回接口,接口内容是token值
3. 前端将token值存储到cookie中,跳转路由到首页
import Cookies from 'js-cookie'
this.$http.post('/login', this.dataForm).then(({ data: res }) => {
if (res.code !== 0) {
// 重新获取验证码
this.getCaptcha()
return this.$message.error(res.msg)
}
// 成功登录
Cookies.set('token', res.data.token)
this.$router.replace({ name: 'home' })
}).catch(() => {})
4. 为什么存储在cookie中?cookie的有效期?
-
因为每次发送请求的时候,请求头中的cookie都会发送,这样token也每次都有发送。
-
axios默认没有携带cookie,设置全局默认携带cookie,axios.defaults.withCredentials = true。
-
前端设置withCredentials的情况下,后端要设置Access-Control-Allow-Origin为你的源地址,例如
http://localhost:8080,而且还要设置header(‘Access-Control-Allow-Credentials: true’);Access-Control-Allow-Origin不能设置为*,不然cookie不会出现在http的请求头里
const http = axios.create({
// 允许携带cookie值
withCredentials: true
})
登录成功后的cookie,token:
- cookie的默认有效期时间是20分钟;前后端都可以设置有效期时间,在项目中是前端设置的有效期时间,1小时
前端设置cookie失效时间:
// 10s后失效自动跳转到登录页面
import Cookies from 'js-cookie'
let seconds = 10;
let expires = new Date(new Date().getTime() + seconds * 1000);
Cookies.set('token', res.data.token, {expires: expires})
5. token失效是前端判断还是后端判断?
后端判断,返回接口,code值为401
6. cookie失效后,跳转到登录页面,前端删除token值
- 获取到接口返回的code值,code值是401,无权限,token过期
/**
* 清除登录信息
*/
export function clearLoginInfo () {
Cookies.remove('token')
}
/**
* 响应拦截
*/
http.interceptors.response.use(response => {
if (response.data.code === 401 || response.data.code === 10001) {
// 清除登录信息
clearLoginInfo()
// 跳转到登录页面
router.replace({ name: 'login' })
return Promise.reject(response.data.msg)
}
return response
}, error => {
console.error(error)
return Promise.reject(error)
})
2、图片验证码?
3、怎么实现A用户打开看到是A页面,B用户打开看到是B页面?
1. 用户登录后,前端请求菜单接口,后端返回菜单接口,存储到全局变量
const routes = [];
const router = new Router({
mode: 'hash',
routes
})
router.beforeEach((to, from, next) => {
// 添加动态(菜单)路由
// 已添加或者当前路由为页面路由, 可直接访问
......
// 获取菜单列表, 添加并全局变量保存
http.get('/sys/menu/nav').then(({ data: res }) => {
// 接口返回数据,存储到全局变量window.SITE_CONFIG['menuList']中
window.SITE_CONFIG['menuList'] = res.data
// 动态添加路由
fnAddDynamicMenuRoutes(window.SITE_CONFIG['menuList'])
next({ ...to, replace: true })
}).catch(() => {
next({ name: 'login' })
})
})
2. 前端处理,动态添加并全局变量保存
- 获取接口返回的菜单列表,添加到全局变量
- 动态添加路由
- 点击侧边栏时,
this.$router.push()跳转到相应页面
/**
* 添加动态(菜单)路由
* @param {*} menuList 菜单列表
* @param {*} routes 递归创建的动态(菜单)路由
*/
function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
for (var i = 0; i < menuList.length; i++) {
.....
// 组装路由
var route = {
path: '',
component: null,
name: '',
meta: {
...window.SITE_CONFIG['contentTabDefault'],
menuId: menuList[i].id,
title: menuList[i].name
}
}
......
URL = URL.replace(/^\//, '').replace(/_/g, '-')
route['path'] = route['name'] = URL.replace(/\//g, '-')
route['component'] = () => import(`@/views/modules/${URL}`)
routes.push(route)
}
......
}
4、如何判断是否显示按钮?
1. 前端请求权限接口,后端返回接口,接口中有对应的按钮字段,存储到全局变量
getPermissions () {
return this.$http.get('/sys/menu/permissions').then(({ data: res }) => {
// 存储到全局变量window.SITE_CONFIG['permissions']
window.SITE_CONFIG['permissions'] = res.data
}).catch(() => {})
}
2. 前端判断是否有此字段,有就显示按钮,没有不显示。
- 组件中使用:
<el-button v-if="$hasPermission('oss:download:add')" type="primary">支持下载</el-button>
<el-button v-if="$hasPermission('0')" type="primary">新增</el-button>
- hasPermission判断有无此字段
/**
* 权限
* @param {*} key
*/
export function hasPermission (key) {
return window.SITE_CONFIG['permissions'].indexOf(key) !== -1 || false
}
// 挂载全局
Vue.prototype.$hasPermission = hasPermission