mirror of
https://gitee.com/dromara/sa-token.git
synced 2024-11-29 18:37:49 +08:00
优化文档结构样式
This commit is contained in:
parent
1224397981
commit
ae67ad6a02
@ -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>
|
||||
|
||||
|
@ -58,7 +58,8 @@ public class CustomSaTokenContextForSpring extends SaTokenContextForSpring {
|
||||
|
||||
其它逻辑保持不变,框架即可正确获取 uri 地址
|
||||
|
||||
!> 注意:步骤一与步骤二需要同步存在,否则可能有前端假传 header 参数造成安全问题
|
||||
> [!ATTENTION| label:风险警告]
|
||||
> 注意:步骤一与步骤二需要同步存在,否则可能有前端假传 header 参数造成安全问题
|
||||
|
||||
|
||||
### 方案二:直接在yml中配置当前项目的网络访问地址
|
||||
|
@ -53,8 +53,6 @@ SaToken 中的所有异常都是继承于 `SaTokenException` 的,也就是说
|
||||
|
||||
### 异常细分状态码-参照表
|
||||
|
||||
!> 部分插件因异常抛出点较少,暂未做状态码细分处理
|
||||
|
||||
#### sa-token-code 核心包
|
||||
|
||||
| code码值 | 含义 |
|
||||
@ -215,6 +213,9 @@ SaToken 中的所有异常都是继承于 `SaTokenException` 的,也就是说
|
||||
| 30303 | Token已超时 |
|
||||
|
||||
|
||||
> [!WARNING| label:注意]
|
||||
> 部分插件因异常抛出点较少,暂未做状态码细分处理
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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群@管理员寻求帮助。
|
||||
|
@ -42,6 +42,7 @@ session.set("name", "张三");
|
||||
|
||||
随着业务推进,我们还可能会遇到一些需要数据隔离的场景:
|
||||
|
||||
> [!NOTE| label:业务场景]
|
||||
> 指定客户端超过两小时无操作就自动下线,如果两小时内有操作,就再续期两小时,直到新的两小时无操作
|
||||
|
||||
那么这种请求访问记录应该存储在哪里呢?放在 Account-Session 里吗?
|
||||
|
@ -25,6 +25,7 @@ sa-token.active-timeout=-1
|
||||
|
||||
两者的区别,可以通过下面的例子体现:
|
||||
|
||||
> [!TIP| label:场景示例]
|
||||
> 1. 假设你到银行要存钱,首先就要办理一张卡 (要访问系统接口先登录)。
|
||||
> 2. 银行为你颁发一张储蓄卡(系统为你颁发一个Token),以后每次存取钱都要带上这张卡(后续每次访问系统都要提交 Token)。
|
||||
> 3. 银行为这张卡设定两个过期时间:
|
||||
|
@ -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`:
|
||||
|
@ -147,7 +147,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
启动网关与子服务,访问测试:
|
||||
|
||||
> 如果通过网关转发,可以正常访问,直接访问子服务会提示:`无效Same-Token:xxx`
|
||||
> [!WARNING| label:越过网关访问]
|
||||
> 如果通过网关转发,可以正常访问。如果直接访问子服务会提示:`无效Same-Token:xxx`
|
||||
|
||||
|
||||
### 三、服务间内部调用鉴权
|
||||
@ -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,保证其高可用
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) -->
|
||||
|
||||
|
@ -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 为同一个)。
|
||||
>
|
||||
> 应该根据自己的架构合理分析是否应该整合数据互通。
|
||||
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
Sa-Token默认的Redis集成方式会把权限数据和业务缓存放在一起,但在部分场景下我们需要将他们彻底分离开来,比如:
|
||||
|
||||
> [!NOTE| label:业务场景]
|
||||
> 搭建两个Redis服务器,一个专门用来做业务缓存,另一台专门存放Sa-Token权限数据
|
||||
|
||||
|
||||
|
@ -15,6 +15,7 @@ sa-token api-sign 模块将帮你轻松解决以上难题。*(此插件是内
|
||||
|
||||
假设我们有如下业务需求:
|
||||
|
||||
> [!NOTE| label:业务场景]
|
||||
> 用户在 A 系统参与活动成功后,活动奖励以余额的形式下发到 B 系统。
|
||||
|
||||
|
||||
|
@ -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)。
|
||||
|
||||
|
@ -52,7 +52,7 @@ SaTempUtil.getTimeout(token);
|
||||
// 删除指定 token
|
||||
SaTempUtil.deleteToken(token);
|
||||
```
|
||||
> 注意: SaTempUtil创建临时token后登陆的用户id与SaToken框架中StpUtil登陆的用户id并不关联,两者相互独立同时存在
|
||||
|
||||
|
||||
### 集成jwt
|
||||
提到 [临时Token认证],你是不是想到一个专门干这件事的框架?对,就是JWT!
|
||||
|
@ -116,7 +116,8 @@ public class SaTokenConfigure{
|
||||
}
|
||||
```
|
||||
|
||||
!> 注意:如果`SaTokenConfigure`继承了`WebMvcConfigurer`等类,可能会造成循环依赖,如果遇到,请新建一个其他配置类完成此项配置
|
||||
> [!WARNING| label:注意]
|
||||
> 如果`SaTokenConfigure`继承了`WebMvcConfigurer`等类,可能会造成循环依赖,如果遇到,请新建一个其他配置类完成此项配置
|
||||
|
||||
|
||||
然后我们就可以在页面上调用 StpLogic 的 API 了,例如:
|
||||
|
@ -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、开放认证接口
|
||||
|
@ -261,8 +261,9 @@ public class SaSso1ClientApplication {
|
||||
|
||||
### 6、跨域模式下的解决方案
|
||||
|
||||
如上,我们使用简单的步骤实现了同域下的单点登录,聪明如你??,马上想到了这种模式有着一个不小的限制:
|
||||
如上,我们使用简单的步骤实现了同域下的单点登录,聪明如你😏,马上想到了这种模式有着一个不小的限制:
|
||||
|
||||
> [!TIP| style:callout]
|
||||
> 所有子系统的域名,必须同属一个父级域名
|
||||
|
||||
如果我们的子系统在完全不同的域名下,我们又该怎么完成单点登录功能呢?
|
||||
|
@ -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 作用域配置
|
||||
|
@ -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中的数据清空,以防旧数据对测试造成干扰
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -5,7 +5,10 @@
|
||||
|
||||
整合示例在官方仓库的`/sa-token-demo/sa-token-demo-webflux`文件夹下,如遇到难点可结合源码进行测试学习
|
||||
|
||||
!> WebFlux 常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章
|
||||
|
||||
> [!WARNING| label:小提示 ]
|
||||
> WebFlux 常用于微服务网关架构中,如果您的应用基于单体架构且非 Reactor 模型,可以先跳过本章
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
@ -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;}
|
@ -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
76
sa-token-doc/static/docsify-plugins/progress.update.js
Normal file
76
sa-token-doc/static/docsify-plugins/progress.update.js
Normal 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)
|
56
sa-token-doc/static/docsify-plugins/sub-nav-draw.js
Normal file
56
sa-token-doc/static/docsify-plugins/sub-nav-draw.js
Normal 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))
|
||||
}
|
||||
})
|
@ -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;}
|
||||
|
||||
/* 小章鱼 */
|
||||
|
@ -37,7 +37,8 @@ StpUtil.checkDisable(10001);
|
||||
StpUtil.login(10001);
|
||||
```
|
||||
|
||||
!> 旧版本在 `StpUtil.login()` 时会自动校验账号是否被封禁,v1.31.0 之后将 校验封禁 和 登录 两个动作分离成两个方法,不再自动校验,请注意其中的逻辑更改。
|
||||
> [!ATTENTION| label:升级注意:]
|
||||
> 旧版本在 `StpUtil.login()` 时会自动校验账号是否被封禁,v1.31.0 之后将 校验封禁 和 登录 两个动作分离成两个方法,不再自动校验,请注意其中的逻辑更改。
|
||||
|
||||
此模块所有方法:
|
||||
``` java
|
||||
|
@ -73,10 +73,10 @@ public class SaTokenConfigure {
|
||||
}
|
||||
```
|
||||
|
||||
##### 注意事项:
|
||||
- 在`[认证函数]`里,你可以写和拦截器里一致的代码,进行路由匹配鉴权,参考:[路由拦截鉴权](/use/route-check)。
|
||||
- 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常。
|
||||
- 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换。
|
||||
> [!WARNING| label:注意事项:]
|
||||
> - 在`[认证函数]`里,你可以写和拦截器里一致的代码,进行路由匹配鉴权,参考:[路由拦截鉴权](/use/route-check)。
|
||||
> - 由于过滤器中抛出的异常不进入全局异常处理,所以你必须提供`[异常处理函数]`来处理`[认证函数]`里抛出的异常。
|
||||
> - 在`[异常处理函数]`里的返回值,将作为字符串输出到前端,如果需要定制化返回数据,请注意其中的格式转换。
|
||||
|
||||
改写 `setError` 函数的响应格式示例:
|
||||
``` java
|
||||
|
@ -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. 后端校验会话已完成二级认证,返回:`仓库删除成功`。
|
||||
|
||||
|
||||
### 指定业务标识进行二级认证
|
||||
|
@ -83,6 +83,7 @@ for (String sessionId : sessionIdList) {
|
||||
请根据业务实际水平合理调用API。
|
||||
|
||||
|
||||
> [!WARNING| label:注意]
|
||||
> 基于活动 Token 的统计方式会比实际情况略有延迟,如果需要精确统计实时在线用户信息建议采用 WebSocket。
|
||||
|
||||
|
||||
|
@ -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`里进行传输。
|
||||
|
||||
|
@ -63,5 +63,6 @@ public class SaTokenConfigure {
|
||||
gfuPSwZsnUhwgz08GTCH4wOgasWtc3odP4HLwXJ7NDGOximTvT4OlW19zeLH
|
||||
```
|
||||
|
||||
!> **更改了 token 生成策略但是不生效?**<br> 把 Redis 中的旧数据清除掉再试试
|
||||
> [!WARNING| label:更改了 token 生成策略但是不生效?]
|
||||
> 把 Redis 中的旧数据清除掉再试试
|
||||
|
||||
|
@ -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>
|
||||
> 前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全:**无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验!**
|
||||
|
||||
|
||||
|
||||
|
@ -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)` 一句代码就完成登录认证。
|
||||
|
||||
除了登录方法,我们还需要:
|
||||
|
||||
|
@ -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、关闭注解校验
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user