优化文档结构样式

This commit is contained in:
click33 2024-07-29 00:43:55 +08:00
parent 1224397981
commit ae67ad6a02
38 changed files with 551 additions and 156 deletions

View File

@ -151,21 +151,53 @@
</a> -->
<div class="main-box">
<!-- 内容区 -->
<div id="app">加载中...</div>
<!-- 右边盒子 -->
<div class="doc-right-bj-box">
<div class="doc-right-bj-box-title">目录</div>
<div class="doc-right-more-item">
<!-- ad盒子 -->
<div class="ad-box">
<div class="ad-title">
<span class="ad-tips">推广信息:</span>
<span class="ad-tips ad-close">关闭</span>
</div>
<!-- ssp -->
<div class="top-ad-box" style="margin-bottom: 12px;">
<a href="http://sa-pro.dev33.cn?from=satop" target="_blank">
<img src="https://oss.dev33.cn/sa-token/ad/sa-sso-pro-s3.png" />
</a>
</div>
<!-- 万维广告div -->
<div class="wwads-cn wwads-horizontal" data-id="88" style="min-height: 0px; border: 1px #eee solid; margin-bottom: 12px;"></div>
</div>
<!-- help 按钮 -->
<div class="help-btn">技术求助</div>
</div>
</div>
</div>
<!-- 万维广告div -->
<div style="position: fixed; right: 0; bottom: 0; z-index: 10000; border: 0px #aaa solid;">
<!-- <div style="position: fixed; right: 0; bottom: 0; z-index: 10000; border: 0px #aaa solid;">
<div class="wwads-cn wwads-vertical" data-id="88" style="max-width:150px"></div>
</div>
</div> -->
<!-- 小助手div -->
<div class="p-none help-btn-box" style="position: fixed; right: 40px; bottom: 330px; z-index: 10000; border: 0px #aaa solid;">
<!-- <div class="p-none help-btn-box" style="position: fixed; right: 40px; bottom: 330px; z-index: 10000; border: 0px #aaa solid;">
<div class="help-tips" style="position: relative; left: -30px; top: -10px;"></div>
<div class="help-btn" style="width: 60px; height: 60px; text-align: center; border-radius: 50%; background-color: #42b983; cursor: pointer;">
<span style="font-size: 18px; color: #FFF; line-height: 60px;">Help</span>
</div>
</div>
</div> -->
<!-- UI逐渐显现 -->
@ -178,6 +210,10 @@
}, 1);
</script>
<!-- jqeury -->
<script src="static/jquery.min.js"></script>
<script src="static/layer-v3.1.1/layer.js"></script>
<!-- -->
<script src="./static/docsify-plugin.js?v=7"></script>
<script src="./static/is-star-plugin.js?v=7"></script>
@ -216,6 +252,28 @@
tabComments: true, // 用注释来标注选项卡标题,例如:<!-- tab:SpringBoot -->
tabHeadings: true // 用标题+粗体来定制选项卡
},
// 阅读进度
progress: {
position: "top",
color: "var(--theme-color,#42b983)",
height: "3px",
},
// 信息提示框
'flexible-alerts': {
style: 'flat', // 默认风格 callout=浅色flat=深色
note: {
label: {}
},
tip: {
label: {},
},
warning: {
label: {}
},
attention: {
label: {}
},
},
// 自定义插件
plugins: [myDocsifyPlugin, window.isStarPlugin, window.isFillInWjPlugin],
}
@ -229,32 +287,69 @@
<script src="static/prism/prism-yaml.min.js"></script>
<script src="static/prism/prism-properties.min.js"></script>
<!-- 文档阅读进度条 -->
<!-- <script src="static/docsify-plugins/progress.update.js"></script> -->
<!-- 右上角次级导航栏 -->
<script src="static/docsify-plugins/sub-nav-draw.js"></script>
<!-- 搜索框 -->
<script src="static/search.min.js"></script>
<!-- 多 tab 切换 -->
<script src="static/docsify-tabs.min.js"></script>
<!-- img点击放大 -->
<script src="static/zoom-image.min.js"></script>
<!-- 好看的提示框 -->
<script src="static/docsify-plugins/docsify-plugin-flexible-alerts.min-1.1.1.js"></script>
<!-- sidebar折叠 -->
<!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/sidebar.min.css" />
<script src="//cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js"></script> -->
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/sidebar.min.css" />
<script src="https://cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js"></script> -->
<!-- jqeury -->
<script src="static/jquery.min.js"></script>
<script src="static/layer-v3.1.1/layer.js"></script>
<!-- 渲染赞助数据 -->
<script src="static/donate/donate-list.js"></script>
<script src="static/donate/donate-fun.js"></script>
<!-- 广告盒子 -->
<script>
if(window.jQuery === undefined || window.Docsify === undefined) {
var str = 'CDN 加载失败,请打开备用地址:<a href="index-backup.html' + location.hash + '" target="_blank">index-backup.html</a>';
document.querySelector('#app').innerHTML = str;
}
(function(){
// 功能6标题下面的广告
if($(window).width() >= 800) {
// 如果一天内用户点击过关闭广告,则不再展现
let allowJg = 1000 * 60 * 60 * 24 * 1;
// allowJg = 1000 * 10;
try{
const closeAdTime = localStorage.closeAdTime;
if(closeAdTime) {
// 点击广告关闭的时间,和当前时间的差距
const closeAdJg = new Date().getTime() - parseInt(closeAdTime);
// 差距小于1天不再展示
if(closeAdJg < allowJg) {
console.log('not show ad ...');
$('.ad-box').remove();
return;
}
}
}catch(e){
console.error(e);
}
// 添加关闭事件
$('.ad-close').click(function(){
console.log('关闭广告');
// $('.top-ad-box').slideUp(); // 折叠收起
layer.confirm('关闭后,一天内不再展现此信息', function(){
$(".ad-box").fadeOut(1000); // 淡出效果
layer.msg('关闭成功');
localStorage.closeAdTime = new Date().getTime();
})
})
}
})();
</script>
<!-- 搜索引擎自动提交 -->
<script>
(function() {
@ -316,17 +411,19 @@
offset: '10%',
})
})
try{
// 给个小提示
const index = layer.tips('框架技术支持,点此求助', '.help-tips', {
tips: [1, '#000'] ,//还可配置颜色
// time: 5000,
});
// 改为 fixed 定位,否则它会随着滚动条移动,样式就跑偏了
$('#layui-layer' + index).css('position', 'fixed');
}catch(e){
console.error(e);
}
// setTimeout(function(){
// try{
// // 给个小提示
// const index = layer.tips('框架技术支持,点此求助', '.help-btn', {
// tips: [1, '#000'] ,//还可配置颜色
// // time: 5000,
// });
// // 改为 fixed 定位,否则它会随着滚动条移动,样式就跑偏了
// $('#layui-layer' + index).css('position', 'fixed');
// }catch(e){
// console.error(e);
// }
// }, 500)
</script>

View File

@ -58,7 +58,8 @@ public class CustomSaTokenContextForSpring extends SaTokenContextForSpring {
其它逻辑保持不变,框架即可正确获取 uri 地址
!> 注意:步骤一与步骤二需要同步存在,否则可能有前端假传 header 参数造成安全问题
> [!ATTENTION| label:风险警告]
> 注意:步骤一与步骤二需要同步存在,否则可能有前端假传 header 参数造成安全问题
### 方案二直接在yml中配置当前项目的网络访问地址

View File

@ -53,8 +53,6 @@ SaToken 中的所有异常都是继承于 `SaTokenException` 的,也就是说
### 异常细分状态码-参照表
!> 部分插件因异常抛出点较少,暂未做状态码细分处理
#### sa-token-code 核心包
| code码值 | 含义 |
@ -215,6 +213,9 @@ SaToken 中的所有异常都是继承于 `SaTokenException` 的,也就是说
| 30303 | Token已超时 |
> [!WARNING| label:注意]
> 部分插件因异常抛出点较少,暂未做状态码细分处理

View File

@ -2,8 +2,7 @@
在线提问链接:[Gitee issue](https://gitee.com/dromara/sa-token/issues)、[GitHub issue](https://github.com/dromara/sa-token/issues)
> 请在新建 issue 时,尽量复制模板格式进行提交
>
> [!TIP| label:请在新建 issue 时,尽量复制模板格式进行提交]
> 1. 提交之前率先参考 <a href="#/more/common-questions" target="_blank">Sa-Token 常见问题解答</a> 以及善用 Gitee issues 搜索功能,查阅问题是否已有答案,已存在的 issue 就不要再重复提交了。
> 2. 问题已得到处理的 issue 请大家及时手动关闭如果超过24小时没有追问我们将默认提交者已找到解决方案关闭issue。
> 3. 有时候 issue 提交之后没有得到及时回复大家可以加入QQ群@管理员寻求帮助。

View File

@ -42,6 +42,7 @@ session.set("name", "张三");
随着业务推进,我们还可能会遇到一些需要数据隔离的场景:
> [!NOTE| label:业务场景]
> 指定客户端超过两小时无操作就自动下线,如果两小时内有操作,就再续期两小时,直到新的两小时无操作
那么这种请求访问记录应该存储在哪里呢?放在 Account-Session 里吗?

View File

@ -25,6 +25,7 @@ sa-token.active-timeout=-1
两者的区别,可以通过下面的例子体现:
> [!TIP| label:场景示例]
> 1. 假设你到银行要存钱,首先就要办理一张卡 (要访问系统接口先登录)。
> 2. 银行为你颁发一张储蓄卡系统为你颁发一个Token以后每次存取钱都要带上这张卡后续每次访问系统都要提交 Token
> 3. 银行为这张卡设定两个过期时间:

View File

@ -5,6 +5,7 @@
虽然在 [开始] 章节已经说明了依赖引入规则但是交流群里不少小伙伴提出bug解决到最后发现都是因为依赖引入错误导致的此处再次重点强调一下
> [!TIP| style:callout]
> **在微服务架构中使用Sa-Token时网关和内部服务要分开引入Sa-Token依赖不要直接在顶级父pom中引入Sa-Token**
总体来讲,我们需要关注的依赖就是两个:`sa-token-spring-boot-starter` 和 `sa-token-reactor-spring-boot-starter`

View File

@ -147,7 +147,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
启动网关与子服务,访问测试:
> 如果通过网关转发,可以正常访问,直接访问子服务会提示:`无效Same-Tokenxxx`
> [!WARNING| label:越过网关访问]
> 如果通过网关转发,可以正常访问。如果直接访问子服务会提示:`无效Same-Tokenxxx`
### 三、服务间内部调用鉴权
@ -229,7 +230,8 @@ Same-Token 默认随 Sa-Token 数据一起保存在Redis中理论上不会存
##### 2、如何主动刷新Same-Token例如五分钟、两小时刷新一次
Same-Token 刷新间隔越短其安全性越高每个Token的默认有效期为一天在一天后再次获取会自动产生一个新的Token
!> 需要注意的一点是Same-Token默认的自刷新机制并不能做到高并发可用多个服务一起触发Token刷新可能会造成毫秒级的短暂服务失效其只能适用于 项目开发阶段 或 低并发业务场景
> [!WARNING| label:注意点]
> 需要注意的一点是Same-Token默认的自刷新机制并不能做到高并发可用多个服务一起触发Token刷新可能会造成毫秒级的短暂服务失效其只能适用于 项目开发阶段 或 低并发业务场景
因此在微服务架构下我们需要有专门的机制主动刷新Same-Token保证其高可用

View File

@ -5,6 +5,19 @@
---
- [[ 公众号 ] 集成sa-token前后端分离部署配置corsFliter解决跨域失效的真正原因](https://mp.weixin.qq.com/s/bSS4vmKlKM7ov_CUkjxkBg) 2024-07-08
- [[ 公众号 ] sa-token前后端分离解决跨域的正确姿势](https://mp.weixin.qq.com/s/96WbWL28T5_-xzyCfJ7Stg) 2024-07-06
- [[ 公众号 ] 集成sa-token实现登录和RBAC权限控制](https://mp.weixin.qq.com/s/SREjXoyL9s1JfddQnU38yA) 2024-04-16
- [[ CSDN ] springboot整合Sa-Token实现登录认证和权限校验万字长文](https://blog.csdn.net/2301_78646673/article/details/136008153) 2024-03-31
- [[ CSDN ]【Sa-Token】9、Sa-Token实现在线用户管理功能](https://blog.csdn.net/qq_40065776/article/details/132180932) 2023-11-01
- [[ CSDN ]【Sa-Token】9、Sa-Token实现在线用户管理功能](https://blog.csdn.net/qq_40065776/article/details/132180932) 2023-11-01
- [[ CSDN ] 【Sa-Token】9、Sa-Token实现在线用户管理功能](https://blog.csdn.net/qq_40065776/article/details/132180932) 2023-08-09
- [[ CSDN ] 【RuoYi-Vue-Plus】学习笔记 31 - Sa-Token登录验证拦截器之 Token 有效期及其续签Sa-Token 源码)](https://blog.csdn.net/Michelle_Zhong/article/details/126071871) 2022-07-30

View File

@ -7,6 +7,11 @@
<table class="gzh-table" style="text-align: center;">
<tr>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=Mzg2Mzg0NjEwOA==&mid=2247485024&idx=1&sn=11883396c1844fd2c4bd208c299bb075&send_time="/>
<b>Java大飞哥</b>
<span>专注软件开发、技术架构设计、源码分享、JAVA技术。</span>
</td>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000004&size=102&__biz=Mzg4Nzg2MjQzNg==&mid=2247484545&idx=1&sn=c6101effb31b639fe2699b56bcc090c7&send_time="/>
<b>小简聊开发</b>
@ -27,7 +32,6 @@
<b>TJ君</b>
<span>一个励志推荐10000款开源项目与免费工具的程序猿</span>
</td>
<td>-</td>
</tr>
<tr>
<td>
@ -137,7 +141,7 @@
<span>推荐热门开源软件,介绍新开源项目,报导开源资讯!</span>
</td>
</tr>
<!-- <tr>
<tr>
<td>
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000004&size=102&__biz=MzUzNTY2NjAzMg==&mid=2247484321&idx=1&sn=52e7e5e0dc03437e94908b6a67985500&send_time="/>
<b>Dromara开源组织</b>
@ -220,10 +224,10 @@
<b>HelloGitHub</b>
<span>分享 GitHub 上有趣、入门级的开源项目。</span>
</td>
</tr> -->
</tr>
</table>
<br>
感谢以上公众号对 Sa-Token 项目的推荐如果您也是java公众号运营者欢迎 [相互推荐](/more/tj-gzh-hz)
感谢以上公众号对 Sa-Token 项目的推荐<!-- 如果您也是java公众号运营者欢迎 [相互推荐](/more/tj-gzh-hz) -->

View File

@ -51,11 +51,11 @@ StpUtil.login(uid, SaLoginConfig.setToken(access_token));
```
### 注意点
数据互通,让前端与后端的交互更加方便,一个 token 即可访问所有接口但也一定程度上失去了OAuth2的 “不同 Client 不同权限” 的设计意义,
同时也默认每个 Client 都拥有了账号的会话权限access_token 与 satoken 为同一个)。
应该根据自己的架构合理分析是否应该整合数据互通。
> [!WARNING| label:注意点]
> 数据互通,让前端与后端的交互更加方便,一个 token 即可访问所有接口但也一定程度上失去了OAuth2的 “不同 Client 不同权限” 的设计意义,
> 同时也默认每个 Client 都拥有了账号的会话权限access_token 与 satoken 为同一个)。
>
> 应该根据自己的架构合理分析是否应该整合数据互通。

View File

@ -3,6 +3,7 @@
Sa-Token默认的Redis集成方式会把权限数据和业务缓存放在一起但在部分场景下我们需要将他们彻底分离开来比如
> [!NOTE| label:业务场景]
> 搭建两个Redis服务器一个专门用来做业务缓存另一台专门存放Sa-Token权限数据

View File

@ -15,6 +15,7 @@ sa-token api-sign 模块将帮你轻松解决以上难题。*(此插件是内
假设我们有如下业务需求:
> [!NOTE| label:业务场景]
> 用户在 A 系统参与活动成功后,活动奖励以余额的形式下发到 B 系统。

View File

@ -25,6 +25,7 @@ implementation 'cn.dev33:sa-token-jwt:${sa.top.version}'
<!---------------------------- tabs:end ---------------------------->
> [!WARNING| label:版本兼容性]
> 1. 注意: sa-token-jwt 显式依赖 hutool-jwt 5.7.14 版本,保险起见:你的项目中要么不引入 hutool要么引入版本 >= 5.7.14 的 hutool 版本。
> 2. hutool 5.8.13 和 5.8.14 版本下会出现类型转换问题,[关联issue](https://gitee.com/dromara/sa-token/issues/I6L429)。

View File

@ -52,7 +52,7 @@ SaTempUtil.getTimeout(token);
// 删除指定 token
SaTempUtil.deleteToken(token);
```
> 注意: SaTempUtil创建临时token后登陆的用户id与SaToken框架中StpUtil登陆的用户id并不关联,两者相互独立同时存在
### 集成jwt
提到 [临时Token认证]你是不是想到一个专门干这件事的框架就是JWT

View File

@ -116,7 +116,8 @@ public class SaTokenConfigure{
}
```
!> 注意:如果`SaTokenConfigure`继承了`WebMvcConfigurer`等类,可能会造成循环依赖,如果遇到,请新建一个其他配置类完成此项配置
> [!WARNING| label:注意]
> 如果`SaTokenConfigure`继承了`WebMvcConfigurer`等类,可能会造成循环依赖,如果遇到,请新建一个其他配置类完成此项配置
然后我们就可以在页面上调用 StpLogic 的 API 了,例如:

View File

@ -2,6 +2,7 @@
在开始SSO三种模式的对接之前我们必须先搭建一个 SSO-Server 认证中心
> [!TIP| label:demo | style:callout]
> 搭建示例在官方仓库的 `/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/`如遇到难点可结合源码进行测试学习demo里有制作好的登录页面
---
@ -71,13 +72,14 @@ implementation 'com.dtflys.forest:forest-spring-boot-starter:1.5.26'
<!---------------------------- tabs:end ---------------------------->
除了 `sa-token-spring-boot-starter``sa-token-sso` 以外,其它包都是可选的:
- 在 SSO 模式三时 Redis 相关包是可选的
- 在前后端分离模式下可以删除 thymeleaf 相关包
- 在不需要 SSO 模式三单点注销的情况下可以删除 http 工具包
建议先完整测试三种模式之后再对pom依赖进行酌情删减。
> [!NOTE| label:引包简化]
> 除了 `sa-token-spring-boot-starter``sa-token-sso` 以外,其它包都是可选的:
>
> - 在 SSO 模式三时 Redis 相关包是可选的
> - 在前后端分离模式下可以删除 thymeleaf 相关包
> - 在不需要 SSO 模式三单点注销的情况下可以删除 http 工具包
>
> 建议先完整测试三种模式之后再对pom依赖进行酌情删减。
### 2、开放认证接口

View File

@ -261,8 +261,9 @@ public class SaSso1ClientApplication {
### 6、跨域模式下的解决方案
如上,我们使用简单的步骤实现了同域下的单点登录,聪明如你??,马上想到了这种模式有着一个不小的限制:
如上,我们使用简单的步骤实现了同域下的单点登录,聪明如你😏,马上想到了这种模式有着一个不小的限制:
> [!TIP| style:callout]
> 所有子系统的域名,必须同属一个父级域名
如果我们的子系统在完全不同的域名下,我们又该怎么完成单点登录功能呢?

View File

@ -45,6 +45,7 @@
### 3、搭建 Client 端项目
> [!TIP| label:demo | style:callout]
> 搭建示例在官方仓库的 `/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/`,如遇到难点可结合源码进行测试学习
#### 3.1、去除 SSO-Server 的 Cookie 作用域配置

View File

@ -2,6 +2,7 @@
如果既无法做到前端同域也无法做到后端同Redis那么可以使用模式三完成单点登录
> [!WARNING| label:小提示]
> 阅读本篇之前请务必先熟读SSO模式二因为模式三仅仅属于模式二的一个特殊场景熟读模式二有助于您快速理解本章内容
@ -14,6 +15,7 @@
所以模式三的主要目标:也就是在 模式二的基础上 解决上述 三个难题
> [!TIP| label:demo | style:callout]
> 模式三的 Demo 示例地址:`/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/`
> [源码链接](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client),如遇难点可参考示例
@ -43,6 +45,7 @@ sa-token.sso-client.is-http=true
- [http://sa-sso-client2.com:9001/](http://sa-sso-client2.com:9001/)
- [http://sa-sso-client3.com:9001/](http://sa-sso-client3.com:9001/)
> [!WARNING| label:小提示]
> 注如果已测试运行模式二可先将Redis中的数据清空以防旧数据对测试造成干扰

View File

@ -4,6 +4,7 @@
整合示例在官方仓库的 `/sa-token-demo/sa-token-demo-solon` 文件夹下,如遇到难点可结合源码进行学习测试。
> [!tip| label:Solon 是什么?]
> Solon 是一个高效的国产应用开发框架:更快、更小、更简单。
>
> - 启动快 5 10 倍;
@ -14,7 +15,6 @@
>
> 详情可参考:[https://solon.noear.org/](https://solon.noear.org/)
---
### 1、创建项目
@ -45,7 +45,7 @@ implementation 'cn.dev33:sa-token-solon-plugin:${sa.top.version}'
Maven依赖一直无法加载成功[参考解决方案](/doc.html#/start/maven-pull)
Maven依赖一直无法加载成功[参考解决方案](https://sa-token.cc/doc.html#/start/maven-pull)
更多内测版本了解:[Sa-Token最新版本](https://gitee.com/dromara/sa-token/blob/dev/sa-token-doc/start/new-version.md)

View File

@ -5,7 +5,10 @@
整合示例在官方仓库的`/sa-token-demo/sa-token-demo-webflux`文件夹下,如遇到难点可结合源码进行测试学习
!> WebFlux 常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章
> [!WARNING| label:小提示 ]
> WebFlux 常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章
---

View File

@ -5,18 +5,102 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
#main h2 {font-size: 1.6rem;}
#main h3 {font-size: 1.25rem;}
.main-box .markdown-section{ padding: 38px 20px; max-width: 70%; margin-left: 12%;}
.main-box .markdown-section{ /* padding: 38px 20px; */ max-width: 100%; /* margin-left: 12%; */}
.main-box .markdown-section h4{font-size: 1rem;}
/* ------- 多设备适配 start ------- */
.sub-nav-draw-box{ display: none; }
body{
--doc-left-width: 300px;
--doc-context-width: 1000px;
--doc-right-width: 300px;
}
/* 大于 1100px就显示左中右结构 */
@media screen and (min-width: 1100px) {
.doc-right-bj-box{ display: block; }
.main-box .content{left: 0;}
.main-box .markdown-section{width: var(--doc-context-width); padding: 38px 20px; border: 0px green solid;}
.main-box .doc-right-bj-box{left: calc(50% + (var(--doc-context-width) / 2) + 10px);}
.main-box .sidebar-nav>ul>li>ul>li>.app-sub-sidebar{
position: fixed;
top: 120px;
left: calc(50% + (var(--doc-context-width) / 2) + 10px);
width: var(--doc-right-width) !important;
border: 0px #000 solid;
line-height: 1.4em;
width: calc(300px - 25px);
max-height: 50vh;
overflow: auto;
}
.main-box .sidebar{width: var(--doc-left-width);}
.main-box .sidebar-nav>ul>li>ul>li>.app-sub-sidebar::-webkit-scrollbar{ width: 0px; }
.main-box .sidebar-nav>ul>li>ul>li>.app-sub-sidebar li.active a{ color: #42B983; }
.main-box .sidebar-nav>ul>li>ul>li>.app-sub-sidebar li a{ font-size: 12px; color: #888; }
/* .main-box .app-sub-sidebar{display: none;} */
}
/* 小于 1100px时 */
@media screen and (max-width: 1100px) {
.doc-right-bj-box{ display: none; }
}
/* 大于 1600px */
@media screen and (min-width: 1600px) {
body{
--doc-left-width: 300px;
--doc-context-width: 1000px;
--doc-right-width: 300px;
}
}
/* 小于 1100px - 1600px 之间 */
@media screen and (max-width: 1600px) {
body{
--doc-left-width: 200px;
--doc-context-width: calc( 100vw - 400px - 50px);
--doc-right-width: calc(200px - 20px);
}
}
/* 小于 1100px时 */
@media screen and (max-width: 1100px) {
.doc-right-bj-box{ display: none; }
}
/* 小于 800px时 */
/* @media screen and (max-width: 800px) {
.doc-right-bj-box{ display: none; }
} */
/* 媒体查询 */
@media screen and (max-width: 800px) {
.nav-left .logo-box .logo-text,
.nav-left .logo-box sub{display: none;}
.main-box .markdown-section{max-width: 1000px; margin-left: auto; margin-top: 40px;}
/* .main-box .markdown-section{max-width: 1000px; margin-left: auto; margin-top: 40px;} */
}
/* 手机端不显示广告,和一些其它东西 */
@media (max-width: 576px) {.wwads-cn,.p-none{display:none!important}}
/* ------- 多设备适配 end ------- */
/* 右侧盒子 */
.doc-right-bj-box{
width: var(--doc-right-width);
padding: 10px;
position: fixed;
margin-top: 10px;
top: 60px;
border: 0px #000 solid;
font-size: 12px;
}
.doc-right-bj-box-title{ font-size: 14px; color: #888; padding-bottom: 8px; border-bottom: 1px #aaa solid; }
.doc-right-more-item{ position: absolute; border: 0px #000 solid; color: #000; width: 100%;}
/* ------- 头部样式 ------- */
.doc-header{position: fixed; top: 0; z-index: 1000; width: 100%; height: 60px; line-height: 60px;}
@ -30,14 +114,14 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
.logo-box sub{margin-left: 5px; color: #666;}
/* 右边导航 */
.doc-header .nav-right{margin: 0; float: right; padding-right: 4em; font-size: 15px;}
.doc-header .nav-right>*{padding: 0px; margin: 0 15px;}
.doc-header .nav-right{margin: 0; float: right; padding-right: 3em; margin-right: 20px !important;}
.doc-header .nav-right>*{padding: 0px; margin: 0 10px;}
.doc-header .nav-right>*:last-child{position: relative; z-index: 1002;}
.doc-header .nav-right>select{border-color: #999; color: #666; outline: 0; cursor: pointer; transition: all 0.2s; background-color: #FFF; border-width: 1px; outline: 0;}
.doc-header .nav-right>select:hover{box-shadow: 0 0 10px #aaa;}
.github-corner{z-index: 1001 !important;}
.doc-header .nav-right .wzi{font-size: 15px; line-height: 61px; transition: color 0.2s; padding-bottom: 4px;}
.doc-header .nav-right .wzi{font-size: 14px; line-height: 61px; transition: color 0.2s; padding-bottom: 4px;}
.doc-header .nav-right .wzi:hover{border-bottom: 2px var(--a-color) solid;}
.nav-right a{color: #34495E;}
@ -74,10 +158,11 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
/* ------- 调整一下左侧树的字体样式 ------- */
.main-box .sidebar{padding-top: 25px; margin-top: 60px;}
.sidebar .sidebar-nav>ul>li>p{font-size: 1.2em; margin-top: 10px;}
.sidebar .sidebar-nav>ul>li> strong{font-size: 1.2em; margin-top: 10px;}
.sidebar .sidebar-nav>ul>li>p{/* font-size: 1.2em; */ margin-top: 10px;}
.sidebar .sidebar-nav>ul>li> strong{/* font-size: 1.2em; */ margin-top: 10px;}
/* .sidebar ul li a{color: #222;} */
.sidebar .sidebar-nav>ul>li>ul>li>a{/* color: #222; */font-size: 16px; /* font-weight: 700; */}
.sidebar .sidebar-nav>ul>li>ul>li>a{/* color: #222; */font-size: 14px; /* font-weight: 700; */}
.main-box .sidebar-nav ul li{margin-top: 0; margin-bottom: 0;}
.main-box .sidebar ul li a{color: #00323c;}
/* 做到悬浮出现下划线的效果 */
@ -89,11 +174,16 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
.main-box .sidebar li.active>a{border: 0px;}
.main-box .sidebar li.active>a:after{content: ''; position: absolute; height: 30px; right: 0; border-right: 3px #42b983 solid;} */
.sidebar .sidebar-nav>ul>li>ul>li.active-rep>a{ color: #42B983; font-weight: 700; }
/* .main-box .sidebar .app-sub-sidebar li:before{float: none;} */
/* ============== code代码样式优化 ================ */
.main-box .markdown-section code, .main-box .markdown-section pre{background-color: rgba(0, 0, 0, 0.04);}
/* 背景变黑 */
.main-box [data-lang]{padding: 0px !important; border-radius: 2px;overflow-x: auto; overflow-y: hidden;}
.main-box [v-pre] code{border: 0px red solid; border-radius: 0px; /* background-color: #282828; */ background-color: #191919; color: #FFF;}
@ -330,30 +420,31 @@ body {
}
.main-box details p{padding: 0 14px;}
/* 顶部广告 */
#main .top-ad-box{padding: 0.5em 1em; font-size: 12px; margin-bottom: 30px; background-color: rgba(0, 0, 0, 0.04);}
#main .top-ad-box a{border-bottom: 0px;}
#main .top-ad-box a:hover{border-bottom: 0px;}
#main .top-ad-box a img{border: 0px #ddd solid; width: 100%; /* max-height: 80px; */
border-radius: 2px; transition: all 0.2s;}
#main .top-ad-box a img:hover{box-shadow: 0 0 20px #ddd;}
.ad-tips{color: #aaa;}
/* 广告盒子 */
.ad-title{ font-size: 14px; color: #aaa; padding-bottom: 8px; margin-bottom: 14px; border-bottom: 1px #aaa solid; }
.ad-tips{margin-bottom: 5px;}
.ad-close{float: right;}
.ad-close:hover{cursor: pointer; text-decoration: underline; color: red;}
.main-box .top-ad-box{font-size: 12px;}
.main-box .top-ad-box a{border-bottom: 0px;}
.main-box .top-ad-box a:hover{border-bottom: 0px;}
.main-box .top-ad-box a img{border: 0px #ddd solid; width: 100%; /* max-height: 80px; */ border-radius: 2px; transition: all 0.2s;}
.main-box .top-ad-box a img:hover{box-shadow: 0 0 20px #ddd;}
/* 帮助按钮 */
.help-btn{transition: all 0.2s;}
.help-btn:hover{box-shadow: 0 0 30px #aaa !important;}
.help-btn{transition: all 0.5s; text-align: center; border: 1px #42b983 solid; background-color: rgba(255, 255, 255, 0.5); cursor: pointer; font-size: 13px; color: #42b983; line-height: 40px;}
.help-btn:hover{box-shadow: 0 0 20px #D1EEE1 !important;}
.xiaozhushou-intro p{line-height: 16px;}
/* 按钮发光动画 */
.help-btn{animation: helpbtnanimation 3s infinite;}
/* .help-btn{animation: helpbtnanimation 3s infinite;}
@keyframes helpbtnanimation{
0%{box-shadow: 0 0 1px #42B983;}
50%{box-shadow: 0 0 20px #42B983;}
100%{box-shadow: 0 0 20px #FFF;}
}
} */
/* ********** 赞助者名单 ******** */
.zanzhu-table{text-align: left;}
@ -374,3 +465,18 @@ body {
.ajax-layer-load.layui-layer-dialog{min-width: 0px !important; background-color: rgba(0,0,0,0.85);}
.ajax-layer-load.layui-layer-dialog .layui-layer-content{padding: 10px 20px 10px 40px; color: #FFF;}
.ajax-layer-load.layui-layer-dialog .layui-layer-content .layui-layer-ico{width: 20px; height: 20px; background-size: 20px 20px; top: 12px; }
/* 万维广告 */
.wwads-cn{margin-top: 0px !important;}
.wwads-cn>a>img{width: 80px !important;}
/* 提示框 */
.main-box .alert{ border-radius: 0px !important; }
/* .main-box .alert ul,.main-box .alert ol{ margin-top: -5px; margin-bottom: -10px; } */
.main-box .alert.tip .title .icon.icon-tip{
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='1em' height='1em' viewBox='0 0 16 16' fill='%2301354d' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' d='M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM8 5.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z'/%3E%3C/svg%3E");
}
.main-box .alert.flat.note{background-color: #E8F4FF;}
.main-box .alert.flat.tip{background-color: #F0F9EB;}
.main-box .alert.flat.warning{background-color: #FDF6EC;}

View File

@ -69,53 +69,55 @@ var myDocsifyPlugin = function(hook, vm) {
}
// 功能6标题下面的广告
if(vm.route.path !== '/' && $(window).width() >= 800) {
var ad = `<p class="top-ad-box">
<span class="ad-tips">推广信息</span>
<span class="ad-tips ad-close">关闭一周内不再显示</span>
<a href="http://sa-pro.dev33.cn?from=satop" target="_blank">
<img src="https://oss.dev33.cn/sa-token/ad/sa-sso-pro-x.png" />
</a>
</p>`;
// if(vm.route.path !== '/' && $(window).width() >= 800) {
// var ad = `<p class="top-ad-box">
// <span class="ad-tips">推广信息:</span>
// <span class="ad-tips ad-close">关闭</span>
// <a href="http://sa-pro.dev33.cn?from=satop" target="_blank">
// <img src="https://oss.dev33.cn/sa-token/ad/sa-sso-pro-s3.png" />
// </a>
// </p>`;
// 没有下划线就先补个下划线
// if($('#main h1').next().prop('tagName') !== 'HR') {
// $('#main h1').after('<hr/>');
// }
// // 没有下划线就先补个下划线
// // if($('#main h1').next().prop('tagName') !== 'HR') {
// // $('#main h1').after('<hr/>');
// // }
// 如果一周内用户点击过关闭广告,则不再展现
let allowJg = 1000 * 60 * 60 * 24 * 7;
// allowJg = 1000 * 10;
try{
const closeAdTime = localStorage.closeAdTime;
if(closeAdTime) {
// 点击广告关闭的时间,和当前时间的差距
const closeAdJg = new Date().getTime() - parseInt(closeAdTime);
// // 如果一周内用户点击过关闭广告,则不再展现
// let allowJg = 1000 * 60 * 60 * 24 * 7;
// // allowJg = 1000 * 10;
// try{
// const closeAdTime = localStorage.closeAdTime;
// if(closeAdTime) {
// // 点击广告关闭的时间,和当前时间的差距
// const closeAdJg = new Date().getTime() - parseInt(closeAdTime);
// 差距小于七天,不再展示
if(closeAdJg < allowJg) {
console.log('not show ad ...');
return;
}
}
}catch(e){
console.error(e);
}
// // 差距小于七天,不再展示
// if(closeAdJg < allowJg) {
// console.log('not show ad ...');
// return;
// }
// }
// }catch(e){
// console.error(e);
// }
// 添加广告
$('#main h1').after(ad);
// 添加关闭事件
$('.top-ad-box .ad-close').click(function(){
console.log('关闭广告');
// $('.top-ad-box').slideUp(); // 折叠收起
layer.confirm('关闭后,一周内不再展现此信息', function(){
$(".top-ad-box").fadeOut(1000); // 淡出效果
layer.msg('关闭成功');
localStorage.closeAdTime = new Date().getTime();
})
})
}
// // 添加广告
// // $('#main h1').after(ad);
// $('.ssp-ad-box').append(ad)
// // 添加关闭事件
// $('.top-ad-box .ad-close').click(function(){
// console.log('关闭广告');
// // $('.top-ad-box').slideUp(); // 折叠收起
// layer.confirm('关闭后,一周内不再展现此信息', function(){
// $(".top-ad-box").fadeOut(1000); // 淡出效果
// layer.msg('关闭成功');
// localStorage.closeAdTime = new Date().getTime();
// })
// })
// }
});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,76 @@
// 显示文档阅读进度的进度条
//
// 修改于https://github.com/HerbertHe/docsify-progress
//
// 1、将最外层盒子的 z-index 值从 999 修改为 9999999999
function plugin(hook, vm) {
let marginTop
hook.mounted(function () {
const content = document.getElementsByClassName("content")[0]
marginTop = parseFloat(
window.getComputedStyle(content).paddingTop.replace("px", "")
)
let insertDOM = `
<div style="position: fixed; width: 100%; z-index: 9999999999; height: ${
window.$docsify["progress"].height
};
${
window.$docsify["progress"].position === "top"
? "top: 0;"
: "bottom: 0;"
}">
<div id="progress-display" style="background-color: ${
window.$docsify["progress"].color
}; width: 0; border-radius: 2px; height: ${
window.$docsify["progress"].height
}; transition: width 0.3s;"></div>
</div>
`
const mainDOM = document.getElementsByTagName("body")[0]
mainDOM.innerHTML = mainDOM.innerHTML + insertDOM
function switcher() {
const body = document.getElementsByTagName("body")[0]
if (!body.classList.contains("close")) {
body.classList.add("close")
} else {
body.classList.remove("close")
}
}
const btn = document.querySelector("div.sidebar-toggle-button")
btn.addEventListener("click", function (e) {
e.stopPropagation()
switcher()
})
})
hook.ready(function () {
window.addEventListener("scroll", function (e) {
let totalHeight =
marginTop +
parseFloat(
window
.getComputedStyle(document.getElementById("main"))
.height.replace("px", "")
)
let scrollTop =
document.body.scrollTop + document.documentElement.scrollTop
let remain = totalHeight - document.body.offsetHeight
document.getElementById("progress-display").style.width =
Math.ceil((scrollTop / remain) * 100) + "%"
})
})
}
// Docsify plugin options
window.$docsify["progress"] = Object.assign(
{
position: "top",
color: "var(--theme-color,#42b983)",
height: "3px",
},
window.$docsify["progress"]
)
window.$docsify.plugins = [].concat(plugin, window.$docsify.plugins)

View File

@ -0,0 +1,56 @@
// 提取次级导航栏显示到右上角
//
// 是否都开右边菜单
let isOpenRightSubTitle = false;
// 重新定位 active-rep 对应的菜单
function positioningVmActiveRep(vm) {
const vmPath = '#' + vm.route.path;
$('.sidebar-nav>ul>li>ul>li>a').each(function(item) {
if($(this).attr('href') === vmPath) {
// $(this).parent().attr('active-rep', true);
$(this).parent().addClass('active-rep')
// console.log($(this));
}
})
}
function subNavDraw(hook, vm) {
// 钩子函数:每次路由切换时数据全部加载完成后调用,没有参数。
hook.doneEach(function () {
// 只在宽屏下展现,太小的屏幕不展现
if(document.body.clientWidth < 1100) {
isOpenRightSubTitle = false;
return;
} else {
isOpenRightSubTitle = true;
}
// 修改高度
const $dom = $('.app-sub-sidebar');
$('.doc-right-more-item').css({ top: ($dom.height() + 80) + 'px' })
// 重新定位 active-rep 对应的菜单
positioningVmActiveRep(vm);
})
// 钩子函数:初始化并第一次加载完成数据后调用,没有参数。
hook.ready(function () {
})
}
window.$docsify.plugins = [].concat(subNavDraw, window.$docsify.plugins)
// 滚动时设置一下左侧滚动条高度,不要超出可视区域
$(document).scroll(function(){
if(isOpenRightSubTitle) {
const offsetTop = $('.active-rep').get(0).offsetTop;
$('.sidebar').scrollTop(offsetTop - ($('.sidebar').height() / 2))
}
})

View File

@ -23,13 +23,13 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica
.logo-box .logo-text {display: inline-block; margin: 0; padding: 0; padding-left: 5px; vertical-align: middle; font-size: 22px;/* font-weight: 700; */}
/* 右边导航 */
.doc-header .nav-right{margin: 0; float: right; line-height: 60px; padding-right: 4em; white-space: nowrap; font-size: 15px; }
.doc-header .nav-right>*{padding: 0px; margin: 0 14px;}
.doc-header .nav-right{margin: 0; float: right; line-height: 60px; padding-right: 4em; white-space: nowrap; }
.doc-header .nav-right>*{padding: 0px; margin: 0 9px;}
.doc-header .nav-right>*:last-child{position: relative; z-index: 1002; }
.nav-right a{color: #34495E; text-decoration: none; transition: all 0.2s;}
.nav-right a:hover{color: #42B983;}
.doc-header .nav-right .wzi{font-size: 15px; line-height: 61px; transition: color 0.2s; padding-bottom: 4px;}
.doc-header .nav-right .wzi{font-size: 14px; line-height: 61px; transition: color 0.2s; padding-bottom: 4px;}
.doc-header .nav-right .wzi:hover{border-bottom: 2px #42B983 solid;}
/* 小章鱼 */

View File

@ -37,7 +37,8 @@ StpUtil.checkDisable(10001);
StpUtil.login(10001);
```
!> 旧版本在 `StpUtil.login()` 时会自动校验账号是否被封禁v1.31.0 之后将 校验封禁 和 登录 两个动作分离成两个方法,不再自动校验,请注意其中的逻辑更改。
> [!ATTENTION| label:升级注意:]
> 旧版本在 `StpUtil.login()` 时会自动校验账号是否被封禁v1.31.0 之后将 校验封禁 和 登录 两个动作分离成两个方法,不再自动校验,请注意其中的逻辑更改。
此模块所有方法:
``` java

View File

@ -73,10 +73,10 @@ public class SaTokenConfigure {
}
```
##### 注意事项:
- 在`[认证函数]`里,你可以写和拦截器里一致的代码,进行路由匹配鉴权,参考:[路由拦截鉴权](/use/route-check)。
- 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常。
- 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换。
> [!WARNING| label:注意事项:]
> - 在`[认证函数]`里,你可以写和拦截器里一致的代码,进行路由匹配鉴权,参考:[路由拦截鉴权](/use/route-check)。
> - 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常。
> - 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换。
改写 `setError` 函数的响应格式示例:
``` java

View File

@ -69,13 +69,13 @@ public SaResult openSafe(String password) {
}
```
调用步骤:
1. 前端调用 `deleteProject` 接口,尝试删除仓库。
2. 后端校验会话尚未完成二级认证,返回: `仓库删除失败,请完成二级认证后再次访问接口`
3. 前端将信息提示给用户,用户输入密码,调用 `openSafe` 接口。
4. 后端比对用户输入的密码完成二级认证有效期为120秒。
5. 前端在 120 秒内再次调用 `deleteProject` 接口,尝试删除仓库。
6. 后端校验会话已完成二级认证,返回:`仓库删除成功`。
> [!NOTE| label:调用步骤:]
> 1. 前端调用 `deleteProject` 接口,尝试删除仓库。
> 2. 后端校验会话尚未完成二级认证,返回: `仓库删除失败,请完成二级认证后再次访问接口`
> 3. 前端将信息提示给用户,用户输入密码,调用 `openSafe` 接口。
> 4. 后端比对用户输入的密码完成二级认证有效期为120秒。
> 5. 前端在 120 秒内再次调用 `deleteProject` 接口,尝试删除仓库。
> 6. 后端校验会话已完成二级认证,返回:`仓库删除成功`。
### 指定业务标识进行二级认证

View File

@ -83,6 +83,7 @@ for (String sessionId : sessionIdList) {
请根据业务实际水平合理调用API。
> [!WARNING| label:注意]
> 基于活动 Token 的统计方式会比实际情况略有延迟,如果需要精确统计实时在线用户信息建议采用 WebSocket。

View File

@ -32,9 +32,8 @@ sa-token.token-prefix=Bearer
此时 Sa-Token 便可在读取 Token 时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx`。
### 注意点
1. Token前缀 与 Token值 之间必须有一个空格。
2. 一旦配置了 Token前缀则前端提交 `Token` 时,必须带有前缀,否则会导致框架无法读取 Token。
3. 由于`Cookie`中无法存储空格字符,也就意味配置 Token 前缀后Cookie 鉴权方式将会失效,此时只能将 Token 提交到`header`里进行传输。
> [!WARNING| label:注意点]
> 1. Token前缀 与 Token值 之间必须有一个空格。
> 2. 一旦配置了 Token前缀则前端提交 `Token` 时,必须带有前缀,否则会导致框架无法读取 Token。
> 3. 由于`Cookie`中无法存储空格字符,所以配置 Token 前缀后Cookie 模式将会失效,此时只能将 Token 提交到`header`里进行传输。

View File

@ -63,5 +63,6 @@ public class SaTokenConfigure {
gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
```
!> **更改了 token 生成策略但是不生效?**<br> 把 Redis 中的旧数据清除掉再试试
> [!WARNING| label:更改了 token 生成策略但是不生效?]
> 把 Redis 中的旧数据清除掉再试试

View File

@ -71,7 +71,7 @@ public class StpInterfaceImpl implements StpInterface {
可参考代码:[码云StpInterfaceImpl.java](https://gitee.com/dromara/sa-token/blob/master/sa-token-demo/sa-token-demo-case/src/main/java/com/pj/satoken/StpInterfaceImpl.java)
> 有同学会产生疑问:我实现了此接口,但是程序启动时好像并没有执行,是不是我写错了?
> [!TIP| label:有同学会产生疑问:我实现了此接口,但是程序启动时好像并没有执行,是不是我写错了?]
> 答:不执行是正常现象,程序启动时不会执行这个接口的方法,在每次调用鉴权代码时,才会执行到此。
@ -162,7 +162,8 @@ StpUtil.hasPermission("index.css"); // false
StpUtil.hasPermission("index.html"); // false
```
!> 上帝权限:当一个账号拥有 `"*"` 权限时,他可以验证通过任何权限码 (角色认证同理)
> [!WARNING| label:上帝权限]
> 当一个账号拥有 `"*"` 权限时,他可以验证通过任何权限码 (角色认证同理)
### 7、如何把权限精确到按钮级
@ -176,19 +177,18 @@ StpUtil.hasPermission("index.html"); // false
2. 前端将权限码集合保存在`localStorage`或其它全局状态管理对象中。
3. 在需要权限控制的按钮上,使用 js 进行逻辑判断,例如在`Vue`框架中我们可以使用如下写法:
``` js
// `arr`是当前用户拥有的权限码数组
// `user.delete`是显示按钮需要拥有的权限码
// `删除按钮`是用户拥有权限码才可以看到的内容。
<button v-if="arr.indexOf('user.delete') > -1">删除按钮</button>
```
其中:`arr`是当前用户拥有的权限码数组,`user.delete`是显示按钮需要拥有的权限码,`删除按钮`是用户拥有权限码才可以看到的内容。
以上写法只为提供一个参考示例,不同框架有不同写法,大家可根据项目技术栈灵活封装进行调用。
注意:以上写法只为提供一个参考示例,不同框架有不同写法,大家可根据项目技术栈灵活封装进行调用。
### 8、前端有了鉴权后端还需要鉴权吗
**需要!**
前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,
为保证服务器安全,**无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!**
> [!ATTENTION| label:前端有了鉴权后端还需要鉴权吗?]
> **需要!** <br>
> 前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全:**无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!**

View File

@ -32,13 +32,13 @@ StpUtil.login(Object id);
```
只此一句代码便可以使会话登录成功实际上Sa-Token 在背后做了大量的工作,包括但不限于:
1. 检查此账号是否之前已有登录;
2. 为账号生成 `Token` 凭证与 `Session` 会话;
3. 记录 Token 活跃时间;
4. 通知全局侦听器xx 账号登录成功;
5. 将 `Token` 注入到请求上下文;
6. 等等其它工作……
6. 等等其它工作……
你暂时不需要完整了解整个登录过程,你只需要记住关键一点:`Sa-Token 为这个账号创建了一个Token凭证且通过 Cookie 上下文返回给了前端`。
@ -61,12 +61,16 @@ public SaResult doLogin(String name, String pwd) {
如果你对以上代码阅读没有压力,你可能会注意到略显奇怪的一点:此处仅仅做了会话登录,但并没有主动向前端返回 token 信息。
是因为不需要吗?严格来讲是需要的,只不过 `StpUtil.login(id)` 方法利用了 Cookie 自动注入的特性,省略了你手写返回 token 的代码。
如果你对 Cookie 功能还不太了解,也不用担心,我们会在之后的 [ 前后端分离 ] 章节中详细的阐述 Cookie 功能,现在你只需要了解最基本的两点:
- Cookie 可以从后端控制往浏览器中写入 token 值。
- Cookie 会在前端每次发起请求时自动提交 token 值。
> [!TIP| label:Cookie 是什么?]
> 如果你对 Cookie 功能还不太了解,也不用担心,我们会在之后的 [ 前后端分离 ] 章节中详细的阐述 Cookie 功能,现在你只需要了解最基本的两点:
>
> - Cookie 可以从后端控制往浏览器中写入 token 值。
> - Cookie 会在前端每次发起请求时自动提交 token 值。
>
> 因此,在 Cookie 功能的加持下,我们可以仅靠 `StpUtil.login(id)` 一句代码就完成登录认证。
因此,在 Cookie 功能的加持下,我们可以仅靠 `StpUtil.login(id)` 一句代码就完成登录认证。
除了登录方法,我们还需要:

View File

@ -3,6 +3,7 @@
---
假设我们有如下需求:
> [!INFO| label:需求场景]
> 项目中所有接口均需要登录认证,只有 “登录接口” 本身对外开放
我们怎么实现呢?给每个接口加上鉴权注解?手写全局拦截器?似乎都不是非常方便。
@ -28,7 +29,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
```
以上代码,我们注册了一个基于 `StpUtil.checkLogin()` 的登录校验拦截器,并且排除了`/user/doLogin`接口用来开放登录(除了`/user/doLogin`以外的所有接口都需要登录才能访问)。
!> `SaInterceptor` 是新版本提供的拦截器,点此 [查看旧版本代码迁移示例](https://blog.csdn.net/shengzhang_/article/details/126458949)。
> [!WARNING| label:版本升级]
> `SaInterceptor` 是新版本提供的拦截器,点此 [查看旧版本代码迁移示例](https://blog.csdn.net/shengzhang_/article/details/126458949)。
### 2、校验函数详解
自定义认证规则:`new SaInterceptor(handle -> StpUtil.checkLogin())` 是最简单的写法,代表只进行登录校验功能。
@ -215,7 +217,10 @@ public SaResult getList() {
请求将会跳过拦截器的校验,直接进入 Controller 的方法中。
**注意点:此注解的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效。**
> [!WARNING| label:注意点]
> 注解 `@SaIgnore` 的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效。
### 7、关闭注解校验

View File

@ -20,6 +20,7 @@ SysUser user = (SysUser) StpUtil.getSession().get("user");
- `Token-Session`: 指的是框架为每个 token 分配的 Session
- `Custom-Session`: 指的是以一个 特定的值 作为SessionId来分配的 Session
> [!TIP| style:callout]
> 有关 Account-Session 与 Token-Session 的详细区别,可参考:[Session模型详解](/fun/session-model)