成果仓库 https://github.com/Gitxieada/Learn_Yhaobo_RunningAccount ,包含vite_vue3_ElementPlus
(主要将Vue2升级Vue3,前端构建工具从 Vue CLI 迁移到 Vite,Element-UI 升级为 Element Plus;优化打包大小)、init.sql 等文件。
本篇文章包含上述项目的学习、效果展示及相关知识点。
Vue3 + Element Plus + ECharts
构建的单页面应用 SPA。SpringBoot2 + JDK1.8 + MyBatis-plus + MySQL + Apache-POI + Bucket4j
, 权限认证管理基于 RBAC 模型, 使用Shiro
框架实现。
本机 mysql 8.0.30。
使用net start
命令查看所有正在运行的服务,其中包括 MySQL 服务。若没有 MySQL 服务,则使用net start mysql
启动。
erp
mysql -u root -p # 进入到了MySQL的命令行工具 mysql> create database erp character set utf8mb4 collate utf8mb4_0900_ai_ci; # 查询数据库是否创建成功 mysql> show databases; mysql> use erp Database changed source ./init.sql;
IDEA 导入 Maven 项目,主要是两种方式。
第一种:在 IDEA 没有项目出于打开状态时,打开新项目,并选择 Maven 导入。第二种:在 IDEA 左上角-file-new-Module from Existing Sources,一路点击,选择带有 Maven 图标的方式进行导入。导入之后会自动识别为 Maven 项目,并在右侧 Maven 面板中可以查看到各个模块。
\src\main\resources的application.yml
,配置 datasource(数据源配置);备份 sql,上传图片(凭证)的主目录
erp.home.location=F:\\java_demoRunningAccount\\data\\
mvn spring-boot:run
。启动之后:
http://localhost:8080/swagger-ui.html
http://localhost:8080/druid/sql.html
之前init.sql初始化数据,rbac_user
表为用户信息。
INSERT INTO `rbac_user` VALUES ('1', 'admin', '71aa075ce3953109527d9b83503cafea', '1');
INSERT INTO `rbac_user` VALUES ('2', 'user', '91d6ac403127709e8973514b454cf4bf', '2');
INSERT INTO `rbac_user` VALUES ('4', 'visitor', 'bb3df98861fc21f3c6e6667d350c62c1', '3');
对应的账号:
username | password |
---|---|
admin | admin123 |
user | user123 |
visitor | visitor123 |
mvn clean package -Dmaven.test.skip=true
。java -jar ./target/erp.jar
。nvm管理node版本:nvm use 18.16.0
。
具体代码见 Learn_Yhaobo_RunningAccount by Gitxieada 仓库的vite_vue3_ElementPlus
文件。
项目在打包以后会产生 dist 目录,确保电脑环境中有类似 serve 这样的本地服务开启工具以后,可以尝试在项目根目录运行 serve -p 8081 ./dist
。
如果没有 serve 则可以全局安装:npm install serve -g
。
1、Dialog 对话框
在 Element-UI 时,通过:visible
属性可控制 Dialog 对话框的显示和隐藏。
当升级到 Element-Plus 时,需要更换成v-model
2、slot 插槽要加父级
在 Element-UI 代码的基础上,把原来的 slot="xxx"
放到新建的父级<template #xxx>
上。
3、Vue3中引入 message 消息提示
第一种:使用 provide
和 inject
方式。
第二种:使用全局挂载$message
方式。
4、float 布局升级为 Flex 布局
如 el-menu 组件,之前的布局需要修改。
5、el-table
<template slot-scope="scope">
</template>
改为
<template #default="scope">
</template>
6、Vue3 的 filter 过滤器代替方法
在 3.x 中,过滤器已移除,且不再支持。取而代之的是,我们建议用方法调用或计算属性来替换它们。
7、点击列表中的图片预览时,图片被表格覆盖问题
在<el-image>
中加入属性preview-teleported="true"
8、vue3 使用 Element-plus Tabs 标签页的点击事件 tab-click
和 Vue 2.x 版本的取值不兼容;注意:获取 name 属性需要 tab.props.name
。
9、按需引入 ECharts 图表和组件
https://echarts.apache.org/handbook/zh/basics/import
用于请求限流的过滤器,基于令牌桶(token-bucket)算法实现。
思路大致是这样的:
首先有一个用来装令牌的桶,它的容积是有限的,例如 20 个。
以一个恒定的速率向桶中注入令牌,例如每秒 10 个。当桶满的时候则扔掉那些无法注入的令牌。
当请求进入时,从桶中取出令牌,然后放行这个请求。每次可以取出的令牌数不一定是 1 个,也可以是多个。
如果请求进入时,桶中无法提供需要足够的令牌,则拒绝这个请求。这时不会消耗令牌。
相较于漏桶算法,令牌桶的优势在于可以更好的应对突发的流量变化,而不是一刀切的以恒定速率限流。
在 shiro 提供的 CacheManager 接口下,默认提供了缓存抽象类 AbstractCacheManager.class ,还提供了一个实现类 MemoryConstrainedCacheManager 来实现缓存(其原理就是利用 HashMap 缓存数据。修改权限信息,就不会立刻生效,因为有缓存,就不会执行 doGetAuthorizationInfo。),但是这个缓存默认是关闭的,我们每次登录,每次访问权限接口都会调用自定义 realm 中的权限认证和身份认证两个方法。
Memory Constrained Cache Manager 翻译过来就是保存在内存中的缓存管理器,由于运行在 jvm 环境下,也可以理解为使用 jvm 的内存保存数据的工具,适合在单实例使用。
一般情况下,使用 shiro 缓存时,只需要关注授权信息缓存,因为认证信息只是一次验证查询,而授权信息需要在每次认证都会执行(访问量大),且一般情况下授权的数据量大。我们每次使用权限的时候,每次都要从数据库中查找权限数据,影响系统的运行效率,所以可以对用户的权限进行缓存。
Shiro 安全管理器 SecurityManager 可以配置缓存,Shiro 可以缓存两类信息,一类是用户认证登录后,登录成功后的用户的信息,它们使用 SessionManager 管理。Shiro 默认使用 Session 会话管理技术,第一次访问被拦截要求认证登录时,会生成 JSESSIONID 在响应头中,可以自行 F12 查看。更好的方案是用 Redis 缓存用户登录后的个人信息,还能实现分布式架构中 Session 共享。第二类信息缓存,也就是用户权限信息缓存,使用 CacheManager 管理。
如果没给 Shiro 配置授权缓存,每次访问接口都会授权,也就是执行 doGetAuthorizationInfo 这个函数方法。但如果加了缓存,会先从缓存中查询是否有权限信息,如果有,就不再执行如上方法。如果没有,就执行然后缓存。
参考 SpringBoot + Shiro + Redis 缓存配置,缓存认证和授权信息
清除缓存设计:
如果用户正常退出,缓存自动清空;
如果用户非正常退出,缓存也自动清空;
如果修改了用户权限,而用户不退出系统,修改的权限无法立即生效。需要开发者变成实现。
Cookie 的 SameSite 属性 - 阮一峰的网络日志
http 域名在浏览器 set-cookie 失败,导致 cookie 中获取不到内容解决方案
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie
Cookie 的 SameSite 属性用来限制第三方 Cookie,从而减少安全风险。它可以设置三个值:Strict、Lax、None。
Strict 最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
Lax 规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。
设置了 Strict 或 Lax 以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。
Chrome 计划将 Lax 变为默认设置。这时,网站可以选择显式关闭 SameSite 属性,将其设为 None。不过,前提是必须同时设置 Secure 属性(Cookie 只能通过 HTTPS 协议发送),否则无效。
基于安全的考虑,需要给 cookie 加上 Secure 和 HttpOnly 属性,HttpOnly 比较好理解,设置 HttpOnly=true 的 cookie 不能被 js 获取到,无法用 document.cookie 打出 cookie 的内容。Secure 属性是说如果一个 cookie 被设置了 Secure=true,那么这个 cookie 只能用 https 协议发送给服务器,用 http 协议是不发送的。会话 cookie 中缺少 Secure 属性会导致攻击者可以通过非 HTTPS 页面窃取到用户的 cookie 信息,造成用户 cookie 信息的泄露。cookie 中的 Secure 指的是安全性。通过设定 cookie 中的 Secure,可以指定 cookie 是否只能通过 https 协议访问。一般的 cookie 使用 HTTP 协议既可访问,如果启用 Secure 属性,则浏览器仅仅会在 HTTPS 请求中向服务端发送 cookie 内容。在 WEB 应用中,对于敏感业务,如:登录或者付款,需要使用 HTTPS 来保证内容的传输安全,而在用户成功获得授权之后,获得的客户端身份 cookie 如果没有设置为 Secure,那么很有可能会被非 HTTPS 页面拿到,从而造成重要的身份泄露。
因为浏览器的同源策略的限制,不同域名间的请求会造成跨域问题(同源策略是客户端的限制,服务端的互相请求不会有跨域问题)。一般场景下解决跨域问题常用的解决方法都是 CORS 解决,即配置服务端接受发起请求的域名。response.header('Access-Control-Allow-Origin', '*'); // *表示支持所有的域名,可以换成具体的域名
。
服务器 server 端要配置 Access-Control-Allow-Credentials
,我们在客户端设置了 withCredentials=true
参数,对应着服务器端要通过在响应 header 中设置 Access-Control-Allow-Credentials = true
来运行客户端携带证书式的访问。通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时传递的 Cookie。