导入依赖
com.github.axet kaptcha ${kaptcha.version}
首先前端先传一个UUID
// 获取验证码
getCaptcha() {
this.dataForm.uuid = getUUID();
this.captchaPath = this.$http.adornUrl(
`/captcha.jpg?uuid=${this.dataForm.uuid}`
);
},
后端:利用kaptcha生成字符串,然后生成对应图片返回。敲黑板:此刻的UUID被保存了,用于后续验证
@Override
public BufferedImage getCaptcha(String uuid) {
if(StringUtils.isBlank(uuid)){
throw new RRException("uuid不能为空");
}
//生成文字验证码
String code = producer.createText();
SysCaptchaEntity captchaEntity = new SysCaptchaEntity();
captchaEntity.setUuid(uuid);
captchaEntity.setCode(code);
//5分钟后过期
captchaEntity.setExpireTime(DateUtils.addDateMinutes(new Date(), 5));
this.save(captchaEntity);
return producer.createImage(code);
}
正式登录时,验证该UUID:是否存在及有没有超出过期时间
@Override
public boolean validate(String uuid, String code) {
SysCaptchaEntity captchaEntity = this.getOne(new QueryWrapper().eq("uuid", uuid));
if(captchaEntity == null){
return false;
}
//删除验证码
this.removeById(uuid);
if(captchaEntity.getCode().equalsIgnoreCase(code) && captchaEntity.getExpireTime().getTime() >= System.currentTimeMillis()){
return true;
}
return false;
}
2.动态菜单路由
src/router/index.js
前置请求
router.beforeEach((to, from, next) => {
// 添加动态(菜单)路由
// 1. 已经添加 or 全局路由, 直接访问
// 2. 获取菜单列表, 添加并保存本地存储
if (router.options.isAddDynamicMenuRoutes || fnCurrentRouteType(to, globalRoutes) === 'global') {
next()
} else {
http({
url: http.adornUrl('/sys/menu/nav'),
method: 'get',
params: http.adornParams()
}).then(({data}) => {
if (data && data.code === 0) {
fnAddDynamicMenuRoutes(data.menuList)
router.options.isAddDynamicMenuRoutes = true
sessionStorage.setItem('menuList', JSON.stringify(data.menuList || '[]'))
sessionStorage.setItem('permissions', JSON.stringify(data.permissions || '[]'))
next({ ...to, replace: true })
} else {
sessionStorage.setItem('menuList', '[]')
sessionStorage.setItem('permissions', '[]')
next()
}
}).catch((e) => {
console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue')
router.push({ name: 'login' })
})
}
})
后端返回:
前端组装:
function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
var temp = []
for (var i = 0; i < menuList.length; i++) {
if (menuList[i].list && menuList[i].list.length >= 1) {
temp = temp.concat(menuList[i].list)
} else if (menuList[i].url && /S/.test(menuList[i].url)) {
menuList[i].url = menuList[i].url.replace(/^//, '')
var route = {
path: menuList[i].url.replace('/', '-'),
component: null,
name: menuList[i].url.replace('/', '-'),
meta: {
menuId: menuList[i].menuId,
title: menuList[i].name,
isDynamic: true,
isTab: true,
iframeUrl: ''
}
}
// url以http[s]://开头, 通过iframe展示
if (isURL(menuList[i].url)) {
route['path'] = `i-${menuList[i].menuId}`
route['name'] = `i-${menuList[i].menuId}`
route['meta']['iframeUrl'] = menuList[i].url
} else {
try {
route['component'] = _import(`modules/${menuList[i].url}`) || null
} catch (e) {}
}
routes.push(route)
}
}
if (temp.length >= 1) {
fnAddDynamicMenuRoutes(temp, routes)
} else {
mainRoutes.name = 'main-dynamic'
mainRoutes.children = routes
router.addRoutes([
mainRoutes,
{ path: '*', redirect: { name: '404' } }
])
sessionStorage.setItem('dynamicMenuRoutes', JSON.stringify(mainRoutes.children || '[]'))
console.log('n')
console.log('%c!<-------------------- 动态(菜单)路由 s -------------------->', 'color:blue')
console.log(mainRoutes.children)
console.log('%c!<-------------------- 动态(菜单)路由 e -------------------->', 'color:blue')
}
}
3.前端权限控制
v-if="isAuth('product:lecinfo:save')"
在动态菜单路由时将这些都存在浏览器的会话存储中
export function isAuth (key) {
return JSON.parse(sessionStorage.getItem('permissions') || '[]').indexOf(key) !== -1 || false
}
存:sessionStorage.setItem(‘permissions’, JSON.stringify(data.permissions || ‘[]’))
(base) xu@xu:~/Desktop/sharing$ netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIME_WAIT 6
FIN_WAIT1 22
CLOSE_WAIT 35
LISTEN 54
ESTABLISHED 294
4.限制XSS
link1 link2
注入的恶意代码有两种类型:
在img或者iframe等标签中,后面接着代码,可能以javascript:开头,。 以


