1、 Cookie and Session
秘钥处理:
//秘钥特点:唯一性,迷惑性 UUID几乎可以保持唯一性
return UUID.randomUUID().toString().replace("-", "");
前端js添加打印result语句,在检查页面获取信息
业务说明:
用户向服务器发起请求,获取服务器的结果,但是请求的生命周期是一次请求一次响应,如果该其你去结束,则结束全部的响应的数据会全部清空;为了保存服务器的响应数据应该想办法将服务器数据持久化。
Cookie说明:
cookie类型是小型文本文件是某些网站为了辨别用户身份,进行session来跟踪而存储在用户本地终端上的数据(经常经过加密),由于用户客户端计算机暂时或永久保存的信息。
1.cookie是一个小型文本文件,存储在本地终端上;
2.cookie可以存储用户信息;
3.cookie的数据是key-value;
4.cookie的数据一般采用加密的方式保存;
5.cookie的数据可以永久保存 ;
Session说明:
1.session称为会话控制;
2.session可以存储用户信息;
3.session数据的生命周期是整个会话,如果关闭则数据清空;
4.session的数据结构是key-value;
5.浏览器session存储的位置;
特点:如果数据需要临时保存则选择session,如果数据需要长时间存储则选择cookie;如果对于安全性要求较高的数据,选用session,如果安全性不高的选用cookie。
2、 用户登录权限
2.1、 实现系统的首页跳转
http://localhost:8080/#/home
编辑前端路由代码index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import ElementUI from '../components/ElementUI.vue'
import Home from '../components/Home.vue'
//使用路由机制
Vue.use(VueRouter)
const routes = [
{path: '/', redirect: '/login'},
{path: '/login', component: Login},
{path: '/elementUI', component: ElementUI},
{path: '/home',component:Home}
]
//路由导航守卫!!!!!!!
const router = new VueRouter({
routes
})
export default router
就可以展现如下页面
2.2、 vue的路由导航守卫(拦截器)
路由(网络用语):网络数据通信时经过的站点。
路由(vue中的路由):
历史:用户请求的网址,在N年以前都是通过后端服务器进行同步跳转
实质:请求和组件之间的关系
2.3、 业务需求
说明:用户在未经登录的条件下,可以直接访问其他页面,导致系统不安全,如果需要控制该漏洞则需要在前端进行权限的校验.
校验的规则:
1.如果用户访问没有token信息,则表示用户没有登录,则需要跳转到登录页面
难点:如何才能实现每一次大的请求都要校验?
方案:拦截器
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import ElementUI from '../components/ElementUI.vue'
import Home from '../components/Home.vue'
//使用路由机制
Vue.use(VueRouter)
const routes = [
{path: '/', redirect: '/login'},
{path: '/login', component: Login},
{path: '/elementUI', component: ElementUI},
{path: '/home',component:Home}
]
//路由对象的定义
const router = new VueRouter({
routes
})
//路由导航守卫!!!!!!!
/*
each遍历
beforeEach:用户每次请求在访问目标网址之前都会被拦截
参数:
to 表示用户请求的网址对象信息
from 表示用户请求的来源
next 表示用户请求的放行
需求:
1.如果用户访问登录页面不拦截直接放行
2.有token放行
3.没有token 跳转登录页面
*/
router.beforeEach((to,from,next)=>{
if(to.path==='/login'){return next()}//直接跳转并且结束代码
//判断是否有token
let token =window.sessionStorage.getItem("token")
if(token !== null){return next()}
//如果数据为空则跳转登录页面
next('/login')
})
//路由对象的使用
export default router
这样可以防止出现直接在改变网址后的地址就会跳转的问题
3、 左侧菜单列表
编辑SQL语句
/* 查询当前父级下的所有子级
条件:父级.id = 子级.parent_id
只查询父子级.
*/
SELECT p.id,p.name,p.parent_id,p.path,p.level,p.created,p.updated,
c.id c_id,c.name c_name,c.parent_id c_parent_id,c.path c_path,c.level c_level,c.created c_created,c.updated c_updated
FROM
(SELECT * FROM rights WHERE parent_id=0) p
LEFT JOIN
rights c
ON p.id=c.parent_id
前端页面js分析
1.生命周期函数 触发ajax请求
//初始化函数
created() {
//动态获取左侧菜单信息
this.getMenuList()
//设定模式选中按钮
this.defaultActive = window.sessionStorage.getItem("activeMenu")
},
2.获取远程服务器数据
logout() {
//1.删除session中的数据
window.sessionStorage.clear()
//2.用户访问登录页面
this.$router.push('/login')
},
async getMenuList() {
const {data: result} = await this.$http.get('/rights/getRightsList')
if(result.status !== 200) return this.$message.error("左侧菜单查询失败")
this.menuList = result.data
},
//设定左侧折叠展开效果
collspseClick() {
this.isCollapse = !this.isCollapse
},
defaultActiveMenu(activeMenu){
//为了实现返回之后的选中效果,应该将数据保存到第三方中sessionStory
window.sessionStorage.setItem("activeMenu",activeMenu)
this.defaultActive = activeMenu
}
3.菜单列表的实现
编辑xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.mapper.RightsMapper">
<select id="getRightsList" resultMap="rightsRM">
SELECT p.id,p.name,p.parent_id,p.path,p.level,p.created,p.updated,
c.id c_id,c.name c_name,c.parent_id c_parent_id,c.path c_path,c.level c_level,c.created c_created,c.updated c_updated
FROM
(SELECT * FROM rights WHERE parent_id=0) p
LEFT JOIN
rights c
ON p.id=c.parent_id
</select>
<!--
完成左侧菜单列表的数据封装 1-2级
-->
<resultMap id="rightsRM" type="Rights" autoMapping="true">
<id property="id" column="id"></id>
<!--封装一对多数据-->
<collection property="children" ofType="Rights">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<result property="parentId" column="c_parent_id"/>
<result property="path" column="c_path"/>
<result property="level" column="c_level"/>
<result property="created" column="c_created"/>
<result property="updated" column="c_updated"/>
</collection>
</resultMap>
</mapper>
controller类
package com.jt.controller;
import com.jt.pojo.Rights;
import com.jt.service.RightsService;
import com.jt.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping("/rights")
public class RightsController {
@Autowired
private RightsService rightsService;
/**
* 业务说明: 完成菜单列表查询 1-2级
* URL: /rights/getRightsList
* 参数: 没有参数
* 返回值: SysResult(List)
*/
@GetMapping("getRightsList")
public SysResult getRightsList(){
List<Rights> list = rightsService.getRightsList();
return SysResult.success(list);
}
}
RightsServiceImpl类
package com.jt.service;
import com.jt.mapper.RightsMapper;
import com.jt.pojo.Rights;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RightsServiceImpl implements RightsService{
@Autowired
private RightsMapper rightsMapper;
@Override
public List<Rights> getRightsList() {
return rightsMapper.getRightsList();
}
}