🎏:你只管努力,剩下的交给时间
🏠 :小破站
Spring Security(第五篇):从单体到前后端分离 ------ JSON 响应与处理器实战
-
- 功能清单与路径一览
- 关键实现(与代码严格对应)
- 可视化演示页:左右布局便于截图
- 实操指南(含你的测试过程)
- [单体 vs 前后端分离:Handler 层面的差异对照](#单体 vs 前后端分离:Handler 层面的差异对照)
- 常见问题与排查
- 总结
- 感谢
我们把"怎么进来"(认证来源:配置/内存/数据库)讲清楚了。进入系统之后,单体应用(服务端渲染)和前后端分离的最大差异并不是"如何认证",而是"响应形式":
- 单体:表单提交,重定向/渲染页面
- 分离:JSON API 请求,返回 JSON(不重定向,不渲染页面)
本篇聚焦"响应处理器(Handler)"在前后端分离场景下的落地:登录成功、登录失败、未登录访问、权限不足、注销成功,都返回一致的 API JSON。
功能清单与路径一览
- 登录(API):POST /api/login(表单键 username/password)
- 注销(API):POST /api/logout
- 公开接口:GET /api/public(无需登录)
- 用户接口:GET /api/user、GET /api/me(需登录)
- 管理员接口:GET /api/admin(需 ADMIN 角色)
- 经理接口:GET /api/manager(需 MANAGER 角色)
- 演示页面:GET /api-demo(可视化操作与查看 JSON 响应)
安全配置采用两条过滤器链:
- /api/** 使用 JSON 响应(JsonAuthenticationHandler/JsonAccessDeniedHandler)
- 其他路径沿用页面流(登录页、控制台等)
关键实现(与代码严格对应)
-
API 过滤器链(只匹配 /api/**)
javahttp.securityMatcher("/api/**") .authorizeHttpRequests(a->a.requestMatchers("/api/public").permitAll() .requestMatchers("/api/admin").hasRole("ADMIN") .requestMatchers("/api/manager").hasRole("MANAGER") .anyRequest().authenticated()) .formLogin(f->f.loginProcessingUrl("/api/login") .successHandler(jsonAuthenticationHandler) .failureHandler(jsonAuthenticationHandler))
-
统一 JSON 返回结构
java@Data @Builder public class ApiResponse<T> { private int code; private String message; private T data; private long timestamp; }
-
登录成功/失败/未认证/注销的 JSON 处理器(节选)
java@Override public void onAuthenticationSuccess(..., Authentication auth){ var info = Map.of("username",auth.getName(),"loginTime",System.currentTimeMillis()); writeJsonResponse(resp,200, ApiResponse.success("登录成功", info)); }
-
权限不足(403)处理(节选)
java@Override public void handle(...){ write403(ApiResponse.forbidden("权限不足,无法访问该资源")); }
可视化演示页:左右布局便于截图
- 页面:/api-demo
- 左侧:API 登录表单与说明;右侧:JSON 响应结果实时显示
页面片段(布局 CSS 已调整为"左侧操作,右侧响应"):
html
<div class="login-response-container">
<div class="login-section">...</div>
<div class="response-section"><div id="responseArea"></div></div>
</div>
实操指南(含你的测试过程)
前置:启动应用(端口 18080),使用数据库认证模式(已内置三类账户):
- dbuser/db123(USER)
- dbadmin/dbadmin123(USER,ADMIN)
- dbmanager/dbmanager123(USER,MANAGER)
登录成功(JSON,不重定向)
-
打开 /api-demo
-
左侧输入:用户名 dbuser,密码 db123
-
点击"API 登录"
-
预期:右侧显示
{ "code":200, "message":"登录成功", "data":{"username":"dbuser", ...} }
-
登录失败(用户名或密码错误)
-
仍在 /api-demo
-
输入:用户名 dbuser,密码 wrong
-
点击"API 登录"
-
预期:右侧显示
{ "code":401, "message":"用户名或密码错误" }
-
访问受保护接口(已登录)
-
点击"调用用户接口"或"获取当前用户信息"
-
预期:右侧显示 200 JSON,包含当前用户名与权限集合
权限不足(403)
-
以 dbuser 登录(无 ADMIN)
-
点击"调用管理员接口"
-
预期:右侧显示
{ "code":403, "message":"权限不足,无法访问该资源" }
注销成功(JSON)
-
点击"API 注销"
-
预期:右侧显示
{ "code":200, "message":"注销成功" }
-
单体 vs 前后端分离:Handler 层面的差异对照
- 单体(页面流)
- 登录成功:302 重定向到 /dashboard
- 登录失败:302 重定向到 /login?error
- 未认证:302 到 /login
- 权限不足:渲染 403 页面
- 注销成功:302 到首页
- 分离(JSON 流,本篇 /api/**)
- 登录成功:200 JSON(不重定向)
- 登录失败:401 JSON
- 未认证:401 JSON
- 权限不足:403 JSON
- 注销成功:200 JSON
常见问题与排查
- 401 但你"自认为登录了":确认是否在 /api/login 登录;/login 与 /api/login 分属两条链
- 403 但你觉得自己是管理员:核对登录账号是否具备 ROLE_ADMIN(dbadmin)
- 跨域(CORS):本项目演示同源访问,若前端独立域名,请在 API 链路上配置 CORS
- CSRF:/api/** 关闭 CSRF;如采用 Cookie 场景,请按需启用并前后配合
总结
- 本篇实现了"相同认证模型,不同响应形态"的演示:/api/** 走 JSON,不影响原页面流
- 通过可视化页面 /api-demo,你可以一屏操作并截图:登录成功、失败、权限不足、注销成功
感谢
感谢你读到这里,说明你已经成功地忍受了我的文字考验!🎉
希望这篇文章没有让你想砸电脑,也没有让你打瞌睡。
如果有一点点收获,那我就心满意足了。
未来的路还长,愿你
遇见难题不慌张,遇见bug不抓狂,遇见好内容常回访。
记得给自己多一点耐心,多一点幽默感,毕竟生活已经够严肃了。
如果你有想法、吐槽或者想一起讨论的,欢迎留言,咱们一起玩转技术,笑对人生!😄
祝你代码无bug,生活多彩,心情常青!🚀