用户登录操作
关于token的说明
1.由于服务器需要标识已登录的用户,所以服务器动态生成一个独一无二的token,返回给用户
2.用户将token保存到本地,方便下次访问时携带
生成UUID(独一无二)
/**
* 思路:
* 1.将密码进行加密处理
* 2.根据username/password查询数据库
* 3.有值:
* 登录成功,返回秘钥
* 没有值:
* 登录失败,返回null
* @param user
* @return
*/
@Override
public String login(User user) {
//1.获取明文
String password = user.getPassword();
//2.加密处理
String md5 = DigestUtils.md5DigestAsHex(password.getBytes());
user.setPassword(md5);
System.out.println(md5);
//3.查询数据库
QueryWrapper<User> queryWrapper= new QueryWrapper<>(user);
//4.获取数据库对象
User userDB = userMapper.selectOne(queryWrapper);
//5.判断登录是否正确
if(userDB == null){
return null;
}
//6.使用UUID动态生成TOKEN,根据当前时间毫秒数+随机数利用hash算法生成
// 几乎可以保证不重复.
String token = UUID.randomUUID().toString()
.replace("-","");
return token;
}
token:用户唯一登录标识,
由session登陆成功时保存: let token = result.data
window.sessionStorage.setItem("token",token),
由路由导航守卫进行判断是否可以登录跳转页面:
let token = window.sessionStorage.getItem("token")
//if(token !==null && token.length>0)
//下列if 解释为: 如果token不为null
if(token){
return next()
}
next("/login")
Session和Cookie
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。有关使用Session 对象的详细信息,请参阅“ASP应用程序”部分的“管理会话”。注意会话状态仅在支持cookie的浏览器中保留。
小结:
1.Session称之为 “会话机制”
2.在浏览器中打开网页 就是一个会话.
3.用户的数据可以保存到会话中,但是有生命周期. 当会话关闭,则数据消失.
Cookie,有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息 [1] 。
说明:
1.cookie是一个小型的文本文件
2.cookie中存储的数据一般都是密文.
3.cookie中的数据的生命周期可控. 几天.几年!!!
session和cookie区别
1.session的数据是临时存储.cookie的数据可以永久保存. (生命周期不同)
2.sesion是浏览器中的一个内存对象!而cookie是一个实际的本地文件. (形式不同).
3.session一般存储是一些涉密数据.cookie一般存储相对公开的数据(免密登录). (安全性)
前端保存用户信息
运用session获取保存用户唯一token,通过路由push跳转页面
login(){
//获取表单对象之后进行数据校验
//valid 表示校验的结果 true表示通过 false表示失败
this.$refs.loginFormRef.validate(async valid => {
//如果没有完成校验则直接返回
if(!valid) return
//如果校验成功,则发起ajax请求
const {data: result} = await this.$http.post('/user/login',this.loginForm)
if(result.status !== 200) return this.$message.error("用户登录失败")
this.$message.success("用户登录成功")
//获取用户token信息
let token = result.data
window.sessionStorage.setItem("token",token)
//用户登录成功之后,跳转到home页面
this.$router.push("/home")
})
}
实现系统首页跳转
权限校验—路由导航守卫
业务需求
前端页面跳转是通过路由进行控制. 规定:
1如果用户没有登录,则只允许访问登录页面.只有登录之后才能访问其它页面.(1.防止未登录通过地址ip直接跳转到页面 2.)
难点: 如何实现用户请求的拦截.
拦截器作用: 拦截用户的请求.
结果1: 请求放行
结果2: 请求拦截,一般配合重定向使用!!
路由导航实现
参数说明:
配置前端路由导航守卫
const router = new VueRouter({
routes
})
/**
* 定义路由导航守卫
* 参数1. to 路由跳转的网址
* 参数2. from 路由从哪里来
* 参数3. next 是一个函数,表示放行或重定向
* next() 放行
* next("/login") 重定向
* 业务实现:
* 核心逻辑: 检查是否有token.
* 如果访问login页面 直接放行.
* 有token 表示已经登录,放行请求
* 没有token 表示用户没有登录,重定向到登录页面
*/
router.beforeEach((to,from,next) => {
if(to.path === "/login"){
return next()
}
//说明用户访问的页面不是login 请求需要校验
//获取token数据.
let token = window.sessionStorage.getItem("token")
//if(token !==null && token.length>0)
//下列if 解释为: 如果token不为null
if(token){
return next()
}
next("/login")
})
左侧菜单列表实现
页面分析
通过后端Controller返回Sysresult.status判断是否显示列表
编辑权限层及代码
表设计分析
说明:
name: 权限名称
parent_id: 父级权限 实现了父子级关系.
path: 一级菜单没有路径的, 二级/三级才有路径.
编辑POJO
说明:
1.当前对象中children属性不属于字段,所以使用@TableField(exist = false)进行标识.
2.权限列表中有父子级关系,所以通过children封装子级
业务接口说明
编辑RightsController
编辑ReghtsService
/**
* 实现思路:
* 1.先查询一级菜单信息 parent_id = 0
* 2.将一级菜单循环遍历 一级菜单对象.
* 3.根据一级菜单信息,查询当前菜单下的二级.
* 4.将查询得到的二级菜单,封装到一级对象中
* 实现思路二(扩展):
* 利用左连接 实现关联查询 封装数据.
* @return
*/
@Override
public List<Rights> getRightsList() {
//1.查询一级列表信息
QueryWrapper<Rights> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id",0);
List<Rights> oneList = rightsMapper.selectList(queryWrapper);
//2.遍历一级列表
for (Rights oneRights : oneList){
//根据一级查询二级
queryWrapper.clear(); //清除之前的条件
queryWrapper.eq("parent_id",oneRights.getId());
List<Rights> twoList = rightsMapper.selectList(queryWrapper);
//将查询的结果封装一级对象中
oneRights.setChildren(twoList);
}
return oneList;
}
用户模块实现
Home组件为父组件,其余为子组件,通过children[{},{}]放入Home路由中
ElementUI学习了解
必须在定义之后,Vue.use声明为全局组件,子组件才可以调用
<template>
<div>
<!-- 标签使用原则:
规则: 先定义,后使用
语法: el-breadcrumb 找到名称为Breadcrumb组件进行展现
定义elementUI的组件: 按需导入组件
从elementUI中导入特定的组件
1.import {Breadcrumb} from 'element-ui'
2.Vue.use(Breadcrumb) 声明为全局组件.子组件可以直接调用
-->
<!-- 1.添加面包屑导航 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>活动管理</el-breadcrumb-item>
<el-breadcrumb-item>活动列表</el-breadcrumb-item>
<el-breadcrumb-item>活动详情</el-breadcrumb-item>
</el-breadcrumb>
<!-- 2.定义卡片视图 -->
<el-card class="box-card">
<div class="text item">
<!-- 4.栅格: 每行24格,可以动态的缩放 -->
<el-row :gutter="20">
<el-col :span="8">
<!-- 3.定义文本输入框-->
<el-input placeholder="请输入内容" v-model="input3" class="input-with-select">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</el-col>
<el-col :span="3">
<el-button type="primary">主要按钮</el-button>
</el-col>
</el-row>
</div>
</el-card>
</div>
</template>
<script>
//对外声明组件属性/方法等参数.要被根组件调用
export default {
data(){
return {
}
}
}
</script>
<style lang="less" scoped>
</style>