@@ -464,6 +536,17 @@
consolePlaceholder: "请选择上方一个实验动作来加载实时输出。",
loadingPrefix: "正在加载 ",
requestFailedPrefix: "请求失败:",
+ authBadge: "鉴权策略学习站",
+ authTitle: "从 JWT 到 Sa-Token 的学习空间",
+ authText: "本区详细对比 JWT 和 Sa-Token,展示各自的拦截器、过滤器和请求链路,帮助你理解两套鉴权策略的生命周期。",
+ jwtLabel: "JWT 登录",
+ jwtSummary: "客户端调用 /access 获取 token,后续带 Authorization: Bearer header,适合 stateless API 学习。",
+ jwtLearnMore: "查看 /api/users/stats 的 header 输出、触发 LearningJwtFilter",
+ satokenLabel: "Sa-Token 流程",
+ satokenSummary: "模拟 Sa-Token 里的 session 状态,观察拦截器、注解、认证缓存的运行差异。",
+ satokenLearnMore: "关注 Sa-Token 注解与拦截器的控制流",
+ filterLabel: "正在观察的过滤器:",
+ tokenLabel: "token 生命周期示意:",
exp1Badge: "实验 1",
exp1Title: "追踪校验链路",
exp1Text: "打开用户实验,先创建一个用户,再用同样邮箱重复创建。对比前端错误提示、DuplicateEmailException 和全局异常处理器。",
@@ -552,6 +635,17 @@
consolePlaceholder: "Select one experiment above to load live output.",
loadingPrefix: "Loading ",
requestFailedPrefix: "Request failed: ",
+ authBadge: "Auth Strategy Studio",
+ authTitle: "Explore JWT vs Sa-Token",
+ authText: "This block contrasts the JWT and Sa-Token flows, visualizing filters, interceptors, and the request chain so you understand lifecycle differences.",
+ jwtLabel: "JWT Login",
+ jwtSummary: "Call /access, receive a bearer token, and include Authorization headers on protected calls to see stateless API behavior.",
+ jwtLearnMore: "Trace headers via /api/users/stats and LearningJwtFilter logs",
+ satokenLabel: "Sa-Token Flow",
+ satokenSummary: "Simulate Sa-Token's session-aware interceptor to highlight how stateful auth handles refresh and annotations.",
+ satokenLearnMore: "Observe how Sa-Token annotations and interceptors gate requests",
+ filterLabel: "Filters in focus:",
+ tokenLabel: "Token lifecycle:"
exp1Badge: "Experiment 1",
exp1Title: "Trace validation",
exp1Text: "Open the user lab, create a user, then repeat with the same email. Compare the frontend error with DuplicateEmailException and the global exception handler.",
@@ -640,6 +734,24 @@
window.learningShell.mountShell({ onLanguageChange: renderLanguage });
renderLanguage();
+
+ function renderAuthBoard() {
+ const insights = window.learningShell.getAuthInsights();
+ document.querySelector("#authStrategy strong[data-i18n='jwtLabel']").textContent = insights.jwt.label;
+ document.querySelector("#authStrategy strong[data-i18n='satokenLabel']").textContent = insights.satoken.label;
+ document.querySelector("#authStrategy p[data-i18n='jwtSummary']").textContent = insights.jwt.summary;
+ document.querySelector("#authStrategy p[data-i18n='satokenSummary']").textContent = insights.satoken.summary;
+ document.querySelector("#authStrategy span[data-i18n='jwtLearnMore']").textContent = insights.jwt.learnMore;
+ document.querySelector("#authStrategy span[data-i18n='satokenLearnMore']").textContent = insights.satoken.learnMore;
+ document.querySelector("#filterList").innerHTML = insights.filters.map(f => `${f}`).join("");
+ const timeline = window.learningShell.getTokenTimeline();
+ const timelineEl = document.getElementById("tokenTimeline");
+ timelineEl.innerHTML = timeline.map(item => `${item.stage}${item.detail}
`).join("");
+ }
+
+ renderAuthBoard();
+
+ window.addEventListener("learning-language-changed", renderAuthBoard);