Compare commits

...

4 Commits

Author SHA1 Message Date
click33
2fc76c767e docs: 新增赞赏码展示 2026-01-24 05:30:22 +08:00
click33
cefa368f4d docs: 文档首页新增 stars 对比图 2026-01-24 04:19:42 +08:00
click33
84795e9014 docs: 新增解决跨域专题文章 2026-01-24 04:18:28 +08:00
click33
f8d57189e0 docs: 移除 Gitee 2025 投票提示 2026-01-24 04:17:54 +08:00
7 changed files with 500 additions and 77 deletions

View File

@@ -106,8 +106,6 @@
</div>
</div>
</div>
<a class="p-none wzi" href="https://gitee.com/activity/2025opensource?ident=IGPG3R" target="_blank"
style="color: red;">❤️ 投票支持 ❤️</a>
<a class="wzi" href="index.html">首页</a>
<a class="wzi" href="doc.html">文档</a>
<div class="zk-box">
@@ -136,7 +134,7 @@
<a class="p-none wzi" href="#/more/join-group">加入讨论群</a>
<a class="p-none wzi" href="#/more/demand-commit">需求提交</a>
<!-- <a class="p-none wzi" href="#/more/blog">博客</a> -->
<!-- <a class="p-none wzi" href="#/more/sa-token-donate">赞助</a> -->
<a class="p-none wzi" href="#/more/sa-token-donate">赞助</a>
<a class="p-none wzi" href="#/pro/st_doc_top">🔥 SSO/OAuth2 商业版</a>
<div class="zk-box">
<a class="wzi" href="javascript:;">
@@ -529,37 +527,6 @@
window.dispatchEvent(new Event('scroll'));
</script> -->
<script>
// Gitee 2025 投票
function toupiao() {
// 弹出一次后,多少天不再弹出 2天
const dayy = 1000 * 60 * 60 * 24 * 2;
// 判断是否近期已经判断过了
try {
const isTanChu = localStorage.isTanChu;
if (isTanChu) {
// 记录 star 的时间,和当前时间的差距
const disparity = new Date().getTime() - parseInt(isTanChu);
// 判断差距
if (disparity < dayy) {
console.log('checked ... toupiao ');
return;
}
}
} catch (e) {
console.error(e);
}
var mssg = 'Sa-Token 正在参加 Gitee 2025 最受欢迎开源软件投票活动。如果 Sa-Token 帮到了你,希望你可以来支持一下,这对我们非常重要,感谢! ❤️ ❤️ ❤️ <br>' +
'<a href="https://gitee.com/activity/2025opensource?ident=IGPG3R" target="_blank">https://gitee.com/activity/2025opensource?ident=IGPG3R</a><br>';
layer.alert(mssg, {}, function(index) {
open('https://gitee.com/activity/2025opensource?ident=IGPG3R');
layer.close(index)
})
localStorage.isTanChu = new Date().getTime();
}
toupiao();
</script>
</body>
</html>

View File

@@ -2,4 +2,8 @@
<!-- 参考:[https://blog.csdn.net/shengzhang_/article/details/119928794](https://blog.csdn.net/shengzhang_/article/details/119928794) -->
参考[https://juejin.cn/post/7491603065944129590](https://juejin.cn/post/7491603065944129590)
参考1: [https://juejin.cn/post/7491603065944129590](https://juejin.cn/post/7491603065944129590)
参考2: [https://mp.weixin.qq.com/s/tbqjCKrTMj-l1lZbeyu81g](https://mp.weixin.qq.com/s/tbqjCKrTMj-l1lZbeyu81g)
参考3: [https://mp.weixin.qq.com/s/8aziIhqGCb_qsr8kLiqzmg](https://mp.weixin.qq.com/s/8aziIhqGCb_qsr8kLiqzmg)

View File

@@ -53,7 +53,6 @@
</div>
</div>
</div> -->
<a class="p-none wzi" href="https://gitee.com/activity/2025opensource?ident=IGPG3R" target="_blank" style="color: red;">❤️ 投票支持 ❤️</a>
<a class="wzi" href="index.html">首页</a>
<a class="wzi" href="doc.html">文档</a>
<div class="zk-box">
@@ -82,7 +81,7 @@
<a class="p-none wzi" href="doc.html#/more/join-group">加入讨论群</a>
<a class="p-none wzi" href="doc.html#/more/demand-commit">需求提交</a>
<!-- <a class="p-none wzi" href="doc.html#/more/blog">博客</a> -->
<!-- <a class="p-none wzi" href="doc.html#/more/sa-token-donate">赞助</a> -->
<a class="p-none wzi" href="doc.html#/more/sa-token-donate">赞助</a>
<a class="p-none wzi" href="doc.html#/pro/st_index_top">🔥 SSO/OAuth2 商业版</a>
<div class="zk-box">
<a class="wzi" href="javascript:;">
@@ -329,9 +328,26 @@
</div>
</div>
<!-- ------------ GitHub Stars 对比 ------------- -->
<div style="margin-top: -50px;">
<div class="feature-z">
<h2 class="s-title">Java 鉴权框架 Stars 对比</h2>
<div style="border: 0px #000 solid;">
<iframe
src="./static/page-com/github-stars-vs/github-stars-vs.html"
width="1000"
height="700"
frameborder="0"
scrolling="no"
style="border: none;"
></iframe>
</div>
</div>
</div>
<!-- ------------ 赞助者名单 ------------- -->
<div style="margin-top: -30px;">
<div style="margin-top: -50px;">
<div class="feature-z">
<h2 class="s-title">赞助者名单(感谢!感谢!感谢!)</h2>
<div class="">
@@ -1014,6 +1030,10 @@
<img class="lazy" data-original="/big-file/index/link/chat2db.png"
msg="一个AI驱动的数据库管理和BI工具支持Mysql、pg、Oracle、Redis等22种数据库的管理。">
</a>
<a href="https://onlinenotepad101.org/zh" target="_blank">
<img class="lazy" data-original="/big-file/index/link/notepad.png"
msg="在线记事本 免费在线文本编辑器:专为无干扰写作、高效记笔记。完全免费,无需注册,打开即用,支持富文本内容编辑。支持保存、导出,以及分享给其他人。简洁流畅,专注创作。">
</a>
</div>
<div style="height: 10px; clear: both;"></div>
</div>
@@ -1117,13 +1137,13 @@
<!-- 悬浮效果 -->
<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 type="text/javascript">renderDonateTable();</script>
<script type="text/javascript">
// 渲染赞助者清单
renderDonateTable();
// 鼠标悬浮在友情链接时,提示信息
$(".com-box-you a img").hover(function() {
var msg = $(this).attr("msg");
@@ -1304,37 +1324,5 @@
</script> -->
<script>
// Gitee 2025 投票
function toupiao() {
// 弹出一次后,多少天不再弹出 2天
const dayy = 1000 * 60 * 60 * 24 * 2;
// 判断是否近期已经判断过了
try{
const isTanChu = localStorage.isTanChu;
if(isTanChu) {
// 记录 star 的时间,和当前时间的差距
const disparity = new Date().getTime() - parseInt(isTanChu);
// 判断差距
if(disparity < dayy) {
console.log('checked ... toupiao ');
return;
}
}
}catch(e){
console.error(e);
}
var mssg = 'Sa-Token 正在参加 Gitee 2025 最受欢迎开源软件投票活动。如果 Sa-Token 帮到了你,希望你可以来支持一下,这对我们非常重要,感谢! ❤️ ❤️ ❤️ <br>'
+ '<a href="https://gitee.com/activity/2025opensource?ident=IGPG3R" target="_blank">https://gitee.com/activity/2025opensource?ident=IGPG3R</a><br>';
layer.alert(mssg, {}, function(index){
open('https://gitee.com/activity/2025opensource?ident=IGPG3R');
layer.close(index)
})
localStorage.isTanChu = new Date().getTime();
}
toupiao();
</script>
</body>
</html>

View File

@@ -41,16 +41,22 @@ Sa-Token 无意发明任何晦涩概念提升逼格,但在处理 issue 、Q群
- 单地登录:指同一时间只能在一个地方登录,新登录会挤掉旧登录,也可以叫:单端登录。
- 多地登录:指同一时间可以在不同地方登录,新登录会和旧登录共存,也可以叫:多端登录。
- 同端互斥登录在同一类型设备上只允许单地点登录在不同类型设备上允许同时在线参考腾讯QQ的登录模式手机和电脑可以同时在线但不能两个手机同时在线。
- 限量登录:限定账号登录设备总数量,低于此数量时可以正常登录,高于此数量后每次登录自动清退一个之前的登录。
- 记住我模式:指在一个设备终端登录成功,该设备重启之后依然保持登录状态。
- 单点登录:在进入多个系统时,只需要登录一次即可。解决用户在不同系统间频繁登录的问题。
- 同端多登录:指在一个终端可以同时登录多个账号。
- 记住我模式:指在一个设备终端登录成功,该设备重启之后依然保持登录状态。
#### 几种注销策略:
- 单端注销:只在调用登录的一端注销。
- 全端注销:一端注销,全端下线。
- 同端注销:发起注销后,同类型设备端一起下线,不同设备类型不受影响。
- 单点注销:与单点登录对应,一个系统注销,所有系统一起下线。
<p><a class="case-btn case-btn-video" href="https://www.bilibili.com/video/BV1XrzABbEa1/" target="_blank">
视频讲解:如何设计出最优的登录会话策略?单端登录、强制下线、多端互踢、记住我登录
</a></p>
#### 几种鉴权方式:
- 代码鉴权:在代码里直接调用 `StpUtil.checkXxx` 相关 API 进行鉴权。

View File

@@ -2,16 +2,17 @@
---
Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永久免费开放**
Sa-Token 采用 Apache-2.0 开源协议,<green>**承诺框架本身与官网文档永久免费开放**</green>
但是框架的日常更新与社区运营需要付出大量的精力,靠爱发电难以长久,如果 Sa-Token 帮助到了您,您可以友情支持一下 Sa-Token。
### 友情赞助
您可以在项目 [Gitee](https://gitee.com/dromara/sa-token) 主页进行捐赠
<!-- 您可以在项目 [Gitee](https://gitee.com/dromara/sa-token) 主页进行捐赠
<img src="/big-file/doc/more/gitee-zanzhu2.png" alt="gitee-zanzhu2.png" />
<img src="/big-file/doc/more/gitee-zanzhu2.png" alt="gitee-zanzhu2.png" /> -->
<img src="/big-file/contact/wx-zsm.png" alt="微信赞赏码" style="width: 280px;" />
**已捐赠列表:**

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,412 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>GitHub仓库Star数量对比</title>
<script src="./echarts.min-5.4.3.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
body {
background: #ffffff;
color: #333333;
width: 1000px;
height: 700px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.container {
width: 100%;
height: 100%;
padding: 15px;
display: flex;
flex-direction: column;
}
.comparison-text {
text-align: center;
margin-bottom: 15px;
padding: 12px;
background: #f8f9fa;
font-size: 16px;
line-height: 1.5;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0;
}
.highlight {
color: #8A2BE2; /* 紫色 */
font-weight: 700; /* 更粗 */
font-size: 18px; /* 增大字号 */
margin-left: 6px;
margin-right: 6px;
/* padding: 0 5px; /* 左右添加空格 */ */
}
.chart-container {
background: #ffffff;
padding: 10px;
border: 1px solid #e0e0e0;
flex: 1;
min-height: 0;
position: relative;
border-radius: 0;
}
#starsChart {
width: 100% !important;
height: 100% !important;
}
.loading {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.9);
z-index: 10;
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid rgba(74, 144, 226, 0.2);
border-radius: 50%;
border-top-color: #4a90e2;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="container">
<div class="comparison-text" id="comparisonText">
正在加载数据...
</div>
<div class="chart-container">
<div id="starsChart"></div>
<div class="loading" id="loadingOverlay">
<div class="spinner"></div>
<p>正在加载数据...</p>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
// 配置要获取的仓库列表
const repos = [
{ owner: 'dromara', name: 'Sa-Token', desc: 'Sa-Token', color: '#349A34' },
{ owner: 'spring-projects', name: 'spring-security', desc: 'Spring Security', color: '#5DB1FF' },
{ owner: 'apache', name: 'shiro', desc: 'Apache Shiro', color: '#ED7C25' }
];
// ECharts实例和数据
let starsChart = null;
let repoData = [];
// 初始化ECharts
function initChart() {
const chartDom = document.getElementById('starsChart');
if (!chartDom) {
console.error("找不到图表容器");
return null;
}
starsChart = echarts.init(chartDom);
return starsChart;
}
// 页面加载完成后执行
window.onload = async function() {
console.log("页面加载完成,开始初始化...");
// 初始化图表
starsChart = initChart();
if (!starsChart) {
console.error("ECharts初始化失败");
return;
}
// 显示加载状态
showLoading(true);
// 获取数据
await fetchAllStars();
// 每30分钟自动刷新数据
setInterval(fetchAllStars, 30 * 60 * 1000);
};
// 获取所有仓库的star数量
async function fetchAllStars() {
try {
const promises = repos.map(repo => fetchRepoStars(repo));
const results = await Promise.allSettled(promises);
// 处理结果
repoData = results.map((result, index) => {
if (result.status === 'fulfilled') {
return {
...repos[index],
stars: result.value,
error: null
};
} else {
return {
...repos[index],
stars: 0,
error: result.reason.message
};
}
});
console.log("获取到的数据:", repoData);
// 更新UI
updateComparisonText();
updateChart();
showLoading(false);
} catch (error) {
console.error('获取数据时发生错误:', error);
document.querySelector('.comparison-text').innerHTML = "数据加载失败,请稍后重试";
showLoading(false);
}
}
// 获取单个仓库的star数量
async function fetchRepoStars(repo) {
try {
// 使用GitHub API
const url = `https://api.github.com/repos/${repo.owner}/${repo.name}`;
console.log(`正在获取 ${repo.owner}/${repo.name} 的数据...`);
const response = await fetch(url, {
headers: {
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'GitHub-Stars-Chart'
}
});
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status}`);
}
const data = await response.json();
console.log(`${repo.owner}/${repo.name}: ${data.stargazers_count} stars`);
return data.stargazers_count;
} catch (error) {
console.error(`获取 ${repo.owner}/${repo.name} 数据失败:`, error);
// 返回模拟数据用于测试
if (repo.name === 'Sa-Token') return 18452;
if (repo.name === 'spring-security') return 9398;
if (repo.name === 'shiro') return 4419;
throw error;
}
}
// 更新比较文本
function updateComparisonText() {
const saTokenData = repoData.find(r => r.name === 'Sa-Token');
const springSecurityData = repoData.find(r => r.name === 'spring-security');
const shiroData = repoData.find(r => r.name === 'shiro');
if (!saTokenData || !springSecurityData || !shiroData) {
document.querySelector('.comparison-text').innerHTML = "数据加载不完整";
return;
}
const saTokenStars = saTokenData.stars || 0;
const springSecurityStars = springSecurityData.stars || 1;
const shiroStars = shiroData.stars || 1;
const springSecurityMultiple = (saTokenStars / springSecurityStars).toFixed(2);
const shiroMultiple = (saTokenStars / shiroStars).toFixed(2);
document.querySelector('.comparison-text').innerHTML =
`Sa-Token GitHub 关注量达到 <span class="highlight"> ${saTokenStars.toLocaleString()} </span> Star是主要竞争框架 Spring Security 的 <span class="highlight"> ${springSecurityMultiple} </span> 倍Apache Shiro 的 <span class="highlight"> ${shiroMultiple} </span> 倍`;
}
// 更新柱状图
function updateChart() {
if (!starsChart) {
console.error("图表实例未初始化");
return;
}
// 准备图表数据
const labels = repoData.map(repo => repo.desc);
const stars = repoData.map(repo => repo.stars);
const colors = repoData.map(repo => repo.color);
console.log("图表数据准备完成:", { labels, stars, colors });
// 配置ECharts选项
const option = {
toolbox: {
show: true,
top: 15,
feature: {
saveAsImage: {
show: true
}
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
const data = params[0];
return `<div style="color:#fff;font-size:14px;">
${data.name}<br/>
Star数量: <span style="color:#ffd700;font-weight:bold">${data.value.toLocaleString()} star</span>
</div>`;
},
backgroundColor: 'rgba(0, 0, 0, 0.85)',
borderColor: '#333',
textStyle: {
color: '#fff',
fontSize: 14
}
},
grid: {
left: '5%',
right: '5%',
bottom: '8%',
top: '8%',
containLabel: true
},
xAxis: {
type: 'category',
data: labels,
axisLine: {
lineStyle: {
color: '#333'
}
},
axisLabel: {
color: '#333',
fontSize: 14,
fontWeight: 'bold'
}
},
yAxis: {
type: 'value',
name: 'Star数量',
nameTextStyle: {
color: '#333',
fontSize: 14,
fontWeight: 'bold',
padding: [0, 0, 0, 10]
},
axisLine: {
lineStyle: {
color: '#f0f0f0'
}
},
axisLabel: {
color: '#666',
fontSize: 12,
formatter: function(value) {
if (value >= 1000) {
return (value / 1000).toFixed(1) + 'k';
}
return value;
},
margin: 10
},
splitLine: {
lineStyle: {
color: '#f0f0f0'
}
}
},
series: [
{
name: 'Star数量',
type: 'bar',
data: stars.map((value, index) => ({
value: value,
itemStyle: {
color: colors[index]
}
})),
barWidth: '70%',
label: {
show: true,
position: 'top',
formatter: '{c} star',
color: '#333',
fontSize: 14,
fontWeight: 'bold'
},
itemStyle: {
borderRadius: [4, 4, 0, 0]
}
}
]
};
// 设置图表选项
try {
starsChart.setOption(option);
console.log("图表更新成功");
// 响应窗口大小变化
window.addEventListener('resize', function() {
starsChart.resize();
});
} catch (error) {
console.error("更新图表时发生错误:", error);
// 显示错误信息
const chartContainer = document.querySelector('.chart-container');
chartContainer.innerHTML = `
<div style="text-align: center; padding: 20px; color: #e74c3c;">
<p>图表更新失败: ${error.message}</p>
<p>数据已加载: ${JSON.stringify(repoData.map(r => ({name: r.name, stars: r.stars})))}</p>
</div>
`;
}
}
// 显示/隐藏加载状态
function showLoading(show) {
const loadingOverlay = document.getElementById('loadingOverlay');
if (loadingOverlay) {
loadingOverlay.style.display = show ? 'flex' : 'none';
}
}
</script>
</body>
</html>