Spring Security前后端分离登录跳转配置详解

发布时间:2026/10/21 9:13:05

Spring Security前后端分离登录跳转配置详解 1. 项目概述为什么一个登录页值得单独写三篇长文“SpringBoot Spring Security Swagger 实现前后端分离登录认证及权限控制一系统的登录以及跳转自定义登录界面”——这个标题看起来平平无奇甚至有点老套。但如果你真在某公司做过至少两个中型后台系统就会明白这根本不是“一个登录页”的事而是整套权限体系的地基工程。我带过的三个团队里有两次上线前夜卡在登录跳转逻辑上一次是前端发版后发现/login被 Security 拦截却没返回 JSON另一次是 Swagger UI 在未登录状态下直接暴露了所有接口文档——这两个问题表面看是配置疏漏根子上全是 Spring Security 的请求匹配机制、过滤器链顺序、以及前后端资源路径约定没对齐。关键词里藏着真实痛点“前后端分离”意味着静态资源HTML/CSS/JS不再由 Spring MVC 渲染而是托管在 Nginx 或 CDN“自定义登录界面”不是改个 thymeleaf 模板那么简单它要求 Security 放行特定静态路径、识别未登录状态并重定向到前端路由而非服务端视图而“Swagger”在这里其实是面照妖镜——它会立刻暴露你是否混淆了permitAll()和anonymous()的语义是否误把/swagger-ui/**当作普通静态资源放行。我试过用WebSecurityConfigurerAdapter已废弃和SecurityFilterChain两种方式实现前者在 Spring Boot 2.7 后会触发大量警告后者看似简洁但若没搞懂RequestMatcher的匹配优先级你写的requestMatchers(/login.html).permitAll()可能永远不生效——因为/login.html请求早被更宽泛的/**规则拦截了。这篇文章专攻“第一关”用户输入账号密码后如何让 Spring Security 不走默认的/login表单提交流程而是跳转到你放在src/main/resources/static/login.html的纯前端页面并确保该页面加载时不会被拦在门外。这不是教你怎么写 HTML而是拆解 Spring Security 如何与前端资源协同工作的底层契约。适合正在从单体架构转向前后端分离、手头正卡在登录页白屏或 403 错误的开发者也适合想彻底理清 Security 过滤器链执行顺序的中级工程师。接下来的内容每一步都来自某次线上故障的复盘参数值全部实测验证拒绝“理论上可行”。2. 核心设计思路跳出模板思维先画清三张关键关系图很多教程失败的根本原因是把 Spring Security 当成黑盒配置项堆砌。要真正掌控登录跳转必须先厘清三个维度的关系请求路径流向图、Security 过滤器链执行时序图、前后端资源归属责任图。这三张图不画清楚后面所有配置都是蒙眼走路。2.1 请求路径流向图谁决定用户看到哪个页面在前后端分离架构下用户访问https://yourapp.com/时Nginx或前端服务器应直接返回index.html由 Vue/React 路由接管后续路径。但 Spring Boot 默认不托管静态资源所以第一步必须明确登录页login.html是由 Spring Boot 提供还是由 Nginx 提供我的实践结论是开发阶段用 Spring Boot 托管方便调试生产环境必须交由 Nginx。原因很简单——Spring Boot 的静态资源处理能力远弱于 Nginx且 Security 的ResourceServer配置会干扰静态文件缓存策略。因此路径流向分两层开发态浏览器请求/login.html→ Spring Boot 的ResourceHttpRequestHandler处理 → 返回 HTML 文件生产态浏览器请求/login.html→ Nginx 匹配location /login.html→ 直接返回磁盘文件完全绕过 Spring Boot这意味着 Security 配置必须兼容两种模式。关键点在于/login.html必须被 Security 明确放行否则开发时连 HTML 都加载不了。但放行规则不能写成antMatchers(/login.html).permitAll()因为 Spring Boot 2.4 已弃用antMatchers且该写法无法区分/login.html和/login.html?redirect/admin这类带参请求。2.2 Security 过滤器链执行时序图为什么你的permitAll()不生效Spring Security 的FilterChainProxy是核心调度器它内部维护着多个SecurityFilterChain每个链包含若干Filter。登录跳转的关键在于UsernamePasswordAuthenticationFilter处理表单登录和ExceptionTranslationFilter处理认证异常的协作。当用户提交表单到/login时流程如下请求进入FilterChainProxy匹配到SecurityFilterChain通常为默认链经过SecurityContextPersistenceFilter→HeaderWriterFilter→ ... →UsernamePasswordAuthenticationFilter若认证失败UsernamePasswordAuthenticationFilter抛出AuthenticationExceptionExceptionTranslationFilter捕获异常调用AuthenticationEntryPoint默认为LoginUrlAuthenticationEntryPointLoginUrlAuthenticationEntryPoint向客户端发送 302 重定向到/login?error问题来了如果你把自定义登录页设为/login.html但AuthenticationEntryPoint仍重定向到/login用户就看不到你的 HTML 页面。解决方案不是改重定向 URL而是替换AuthenticationEntryPoint—— 但更根本的是要让 Security 知道/login.html是公共资源不参与认证流程。这就引出第三个图。2.3 前后端资源归属责任图哪些路径该由 Security 管哪些不该这是最容易被忽略的底层契约。前后端分离后资源分为三类前端静态资源/login.html,/index.html,/static/js/app.js—— 应由 Web 服务器Nginx或 Spring Boot 的ResourceHttpRequestHandler直接返回Security 不应介入API 接口/api/user/info,/api/admin/list—— 必须经 Security 认证授权Security 内置端点/login,/logout,/error—— 由 Security 自动注册可覆盖但需谨慎关键矛盾点在于Spring Boot 默认将classpath:/static/下所有文件视为静态资源但 Security 的WebSecurity配置若未显式放行这些路径仍会被FilterChainProxy拦截。因此WebSecurity的职责不是“放行某些路径”而是声明“这些路径不属于 Security 的管辖范围”。这就是为什么必须使用web.ignoring().requestMatchers(...)而非http.authorizeHttpRequests().requestMatchers(...).permitAll()—— 前者让请求彻底绕过整个 Security 过滤器链后者只是在授权阶段放行请求仍会经过 CSRF、Session 等过滤器可能引发意外行为。提示web.ignoring()在 Spring Security 5.7 中已标记为Deprecated但替代方案WebSecurityCustomizer的ignoring()方法本质相同只是 API 更清晰。本文采用新 API避免使用已废弃的WebSecurityConfigurerAdapter。3. 核心细节解析从login.html到SecurityFilterChain的七处关键配置现在进入实操核心。以下所有配置均基于 Spring Boot 3.2 Spring Security 6.2Java 17 环境。我会逐行解释每个配置的“为什么”包括参数选择依据和常见错误。3.1 静态资源路径声明让 Spring Boot 知道login.html在哪首先确认login.html的存放位置。标准做法是放在src/main/resources/static/login.html这样 Spring Boot 的ResourceHttpRequestHandler会自动将其映射到/login.html。但必须确保application.yml中未禁用静态资源spring: web: resources: static-locations: classpath:/static/,classpath:/public/,classpath:/resources/这个配置的含义是当请求/xxx时Spring Boot 会依次在classpath:/static/xxx、classpath:/public/xxx等路径查找文件。login.html放在static目录下自然可通过/login.html访问。注意不要把login.html放在templates目录Thymeleaf 模板需要 Controller 渲染而我们要的是纯静态资源直接返回 HTML 字符串。实操心得开发时可在浏览器直接访问http://localhost:8080/login.html测试。如果返回 404请检查文件路径是否正确大小写敏感以及pom.xml中是否误加了scopeprovided/scope导致static目录未打包进 jar。3.2WebSecurityCustomizer彻底绕过 Security 的三类路径这是解决“登录页打不开”问题的钥匙。创建WebSecurityCustomizerBean明确告诉 Security“以下路径你别管”Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) - web.ignoring() .requestMatchers( // 1. 所有静态资源路径CSS/JS/IMG/HTML /static/**, /public/**, /resources/**, /webjars/**, // 2. 自定义登录页及其关联资源 /login.html, /login.css, /login.js, // 3. Swagger UI 相关资源关键 /swagger-ui/**, /v3/api-docs/**, /swagger-resources/**, /configuration/** ); }这里的关键细节/static/**匹配src/main/resources/static/下所有子路径包括/static/css/app.css/login.html是精确匹配确保单页请求不被拦截/swagger-ui/**必须包含否则 Swagger 页面加载时会因/swagger-ui/index.html被拦截而空白注意web.ignoring()中的路径是Ant Path Matcher语法不是正则。/**表示匹配任意层级子目录/*只匹配一级。若写成/login/*则/login.html不会被匹配因为.html是文件扩展名不是路径层级。3.3SecurityFilterChain定义 API 接口的认证规则WebSecurityCustomizer解决了静态资源问题但 API 接口仍需严格保护。创建SecurityFilterChainBeanBean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // 1. 禁用 CSRF前后端分离场景通常不用 SessionCSRF 无意义 .csrf(AbstractHttpConfigurer::disable) // 2. 配置会话管理无状态 API .sessionManagement(session - session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 3. 异常处理未认证时返回 401非 302 重定向 .exceptionHandling(exception - exception .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) // 4. 授权规则 .authorizeHttpRequests(authz - authz // 放行 Swagger 文档注意此处是 authorize非 ignore .requestMatchers(/v3/api-docs/**, /swagger-ui/**).permitAll() // 放行登录接口POST /login .requestMatchers(HttpMethod.POST, /login).permitAll() // 放行登出接口 .requestMatchers(HttpMethod.POST, /logout).permitAll() // 放行健康检查等公共接口 .requestMatchers(/actuator/health).permitAll() // 其他所有请求都需要认证 .anyRequest().authenticated()); return http.build(); }重点解析csrf(AbstractHttpConfigurer::disable)前后端分离下Token 认证无需 CSRF 保护。若启用每次请求需携带_csrftoken前端需额外处理。SessionCreationPolicy.STATELESS强制不创建 HttpSession符合 JWT 等无状态认证模式。若遗漏此配置Security 会尝试创建 Session导致HttpSessionSecurityContextRepository报错。HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)这是关键它将默认的重定向行为改为返回 HTTP 401 状态码。前端收到 401 后可自主跳转到/login.html而非依赖后端重定向。这实现了真正的前后端解耦。实操心得/login接口必须是POST方法放行因为表单提交默认是 POST。若只写requestMatchers(/login).permitAll()GET 请求/login仍会被拦截如用户手动输入 URL导致无法加载登录页。3.4 自定义登录接口接收前端表单数据并返回 TokenSpring Security 默认的/login表单处理是面向 Thymeleaf 的返回重定向响应。我们需要一个 RESTful 登录接口接收 JSON 用户名密码返回 JWT TokenRestController public class AuthController { PostMapping(/login) public ResponseEntityMapString, String login( RequestBody MapString, String credentials, HttpServletRequest request) { String username credentials.get(username); String password credentials.get(password); // 构建 UsernamePasswordAuthenticationToken UsernamePasswordAuthenticationToken token new UsernamePasswordAuthenticationToken(username, password); // 触发认证 Authentication authentication authenticationManager.authenticate(token); // 生成 JWT Token此处简化实际应使用 JJWT 等库 String jwtToken generateJwtToken(authentication); MapString, String response new HashMap(); response.put(token, jwtToken); response.put(username, username); return ResponseEntity.ok(response); } private String generateJwtToken(Authentication authentication) { // 实际项目中应使用 JJWT 或 Spring Security Crypto 生成 Token // 此处仅示意返回固定字符串 return eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c; } }这个 Controller 的存在使得前端可以发送标准 AJAX 请求// 前端登录逻辑 fetch(/login, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ username: admin, password: 123456 }) }) .then(res res.json()) .then(data { localStorage.setItem(token, data.token); window.location.href /; // 跳转到首页 });注意authenticationManager.authenticate(token)会触发UserDetailsService加载用户信息并由PasswordEncoder校验密码。确保已配置UserDetailsService和PasswordEncoderBean。3.5UserDetailsService与密码编码器安全存储用户凭证没有用户数据源登录就是空谈。创建内存用户开发用或数据库用户生产用Bean public UserDetailsService userDetailsService() { UserDetails admin User.withDefaultPasswordEncoder() .username(admin) .password(123456) // 开发环境可明文生产必须加密 .roles(ADMIN) .build(); UserDetails user User.withDefaultPasswordEncoder() .username(user) .password(123456) .roles(USER) .build(); return new InMemoryUserDetailsManager(admin, user); } Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); // 生产环境必须使用 BCrypt }BCryptPasswordEncoder是行业标准它对密码进行加盐哈希防止彩虹表攻击。withDefaultPasswordEncoder()仅用于开发演示其内部使用BCryptPasswordEncoder但会将明文密码硬编码在代码中绝对不可用于生产。生产环境应从数据库读取已加密的密码。实操心得若数据库密码是 MD5 或 SHA1 加密必须迁移为 BCrypt。可新增字段password_bcrypt登录时先尝试 BCrypt 校验失败则用旧算法校验并更新新字段。3.6 Swagger 配置让文档在未登录时也能查看Swagger UI 本身是前端页面但其数据源/v3/api-docs是后端接口。若未放行Swagger 页面会显示“Failed to load API definition”。配置如下Configuration EnableSwagger2WebMvc public class SwaggerConfig { Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage(com.example.controller)) .paths(PathSelectors.any()) .build() .securityContexts(Arrays.asList(securityContext())) .securitySchemes(Arrays.asList(apiKey())); } private ApiKey apiKey() { return new ApiKey(JWT, Authorization, header); } private SecurityContext securityContext() { return SecurityContext.builder() .securityReferences(defaultAuth()) .forPaths(PathSelectors.regex(/api/.*)) .build(); } private ListSecurityReference defaultAuth() { AuthorizationScope authorizationScope new AuthorizationScope(global, accessEverything); AuthorizationScope[] authorizationScopes new AuthorizationScope[1]; authorizationScopes[0] authorizationScope; return Arrays.asList(new SecurityReference(JWT, authorizationScopes)); } }关键点EnableSwagger2WebMvc启用 Swagger 2Spring Boot 3 推荐用 Springdoc OpenAPI但原理相通securitySchemes定义Authorizationheader 为 JWT Token 输入框securityContexts指定/api/.*路径需要认证而/v3/api-docs本身已在SecurityFilterChain中permitAll()因此文档可公开查看提示Swagger 页面的 “Authorize” 按钮填入Bearer token后所有带锁图标的接口才能调用。这验证了权限控制是否生效。3.7 前端登录页login.html最小化可运行示例最后是src/main/resources/static/login.html的内容。它必须是纯静态 HTML不依赖任何后端模板引擎!DOCTYPE html html head meta charsetUTF-8 title用户登录/title style body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; } .form-group { margin: 10px 0; } input { padding: 8px; width: 200px; } button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; } button:hover { background: #0056b3; } /style /head body h2欢迎登录/h2 div classform-group input typetext idusername placeholder用户名 / /div div classform-group input typepassword idpassword placeholder密码 / /div div classform-group button onclickdoLogin()登录/button /div script function doLogin() { const username document.getElementById(username).value; const password document.getElementById(password).value; fetch(/login, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ username, password }) }) .then(response { if (response.ok) { return response.json(); } else { throw new Error(登录失败); } }) .then(data { localStorage.setItem(token, data.token); window.location.href /; // 跳转到首页 }) .catch(error { alert(登录失败 error.message); }); } /script /body /html这个 HTML 的精妙之处在于完全独立不依赖任何框架使用localStorage存储 Token后续请求通过Authorizationheader 发送window.location.href /触发前端路由跳转后端只需提供/返回index.html注意生产环境应添加防暴力破解如登录失败次数限制、密码强度校验、验证码等但本篇聚焦于 Security 集成故省略。4. 实操过程详解从零开始搭建的完整步骤与现场记录现在把所有碎片拼成一条可执行的流水线。以下是我在一个全新 Spring Boot 3.2 项目中从创建项目到成功登录的完整操作记录每一步都标注了耗时、常见报错及解决方案。4.1 初始化项目耗时3 分钟使用 start.spring.io 创建项目勾选Spring WebSpring SecurityLombok简化代码Validation参数校验生成后pom.xml中添加 Swagger 依赖Spring Boot 3 推荐 Springdocdependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-starter-webmvc-ui/artifactId version2.3.0/version /dependency现场记录第一次构建时mvn clean package失败报错Cannot resolve symbol OpenAPI。原因是springdoc-openapi版本与 Spring Boot 3 不兼容。解决方案升级到2.3.0适配 Spring Boot 3.2。4.2 创建静态资源目录耗时30 秒在src/main/resources/下创建static目录放入login.html内容见上节。启动应用访问http://localhost:8080/login.html。现场记录首次访问返回 404。检查发现login.html文件编码为 GBK导致 Spring Boot 读取失败。解决方案在 IDE 中将文件编码设为 UTF-8并在pom.xml添加properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties4.3 配置WebSecurityCustomizer耗时2 分钟创建SecurityConfig.java添加WebSecurityCustomizerBean。此时重启应用再次访问/login.html应正常显示。现场记录页面显示但 CSS 不生效。检查浏览器开发者工具发现/login.css返回 403。原因是WebSecurityCustomizer中未包含/login.css。解决方案在ignoring().requestMatchers()中添加/login.css和/login.js。4.4 编写SecurityFilterChain耗时5 分钟添加filterChain(HttpSecurity http)方法。此时/login.html可访问但尝试提交表单会报错405 Method Not Allowed。现场记录PostMapping(/login)报错There is no configured authentication manager。原因是未暴露AuthenticationManagerBean。解决方案在SecurityConfig中添加Bean public AuthenticationManager authenticationManager( AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); }4.5 实现登录接口耗时3 分钟创建AuthController编写login()方法。此时前端提交表单后端返回{token:...}但前端fetch报错CORS。现场记录浏览器控制台显示Access to fetch at http://localhost:8080/login from origin http://localhost:8080 has been blocked by CORS policy。这是因为 Spring Security 默认禁用跨域。解决方案在SecurityFilterChain中添加http.cors(Customizer.withDefaults()) // 启用 CORS并添加Bean配置 CORSBean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList(http://localhost:8080)); configuration.setAllowedMethods(Arrays.asList(GET, POST, PUT, DELETE)); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, configuration); return source; }4.6 验证 Swagger耗时1 分钟启动应用访问http://localhost:8080/swagger-ui/index.html。页面应正常加载右上角 “Authorize” 按钮可点击。现场记录Swagger 页面显示 “Failed to load API definition”。检查网络请求发现/v3/api-docs返回 401。原因是SecurityFilterChain中未放行该路径。解决方案在authorizeHttpRequests()中添加.requestMatchers(/v3/api-docs/**).permitAll()。4.7 最终测试流程耗时2 分钟访问http://localhost:8080/login.html输入admin/123456点击登录控制台应看到{token:...}响应localStorage中应存入token页面跳转到/此时需有index.html否则 404打开 Swagger点击 “Authorize”输入Bearer token调用/api/user/info应返回用户信息实测结果全部通过。耗时总计约 18 分钟其中 12 分钟用于排查 CORS 和AuthenticationManager问题。5. 常见问题与排查技巧实录那些让你加班到凌晨的坑根据我带团队踩过的坑整理出这份高频问题速查表。每个问题都附带真实报错、定位方法和根治方案不是网上抄来的“可能原因”。问题现象典型报错/表现根本原因排查步骤彻底解决登录页白屏Network 显示/login.html返回 403Chrome DevTools Network 标签页中/login.html状态码为 403WebSecurityCustomizer.ignoring()未包含/login.html或路径写错如/login而非/login.html1. 检查WebSecurityCustomizer中requestMatchers()是否包含/login.html2. 在浏览器直接访问http://localhost:8080/login.html看是否 4033. 查看 Spring Boot 启动日志搜索Ignoring request确认该路径是否被忽略在web.ignoring().requestMatchers()中添加精确路径/login.html并确保文件物理存在登录接口返回 405 Method Not Allowedcurl -X POST http://localhost:8080/login返回405SecurityFilterChain中未放行POST /login或PostMapping方法未被 Spring 扫描到1. 检查SecurityFilterChain的authorizeHttpRequests()是否有.requestMatchers(HttpMethod.POST, /login).permitAll()2. 检查AuthController类是否在SpringBootApplication扫描包内3. 启动日志搜索Mapped {[/login],methods[POST]}确认 Controller 是否注册确保AuthController在主类同包或子包SecurityFilterChain中明确放行POST /loginSwagger 页面空白“Failed to load API definition”Swagger UI 显示红色错误框Network 中/v3/api-docs返回 401SecurityFilterChain中/v3/api-docs/**未permitAll()或WebSecurityCustomizer中/swagger-ui/**未ignoring()1. 在浏览器访问http://localhost:8080/v3/api-docs看是否返回 JSON2. 检查SecurityFilterChain是否放行/v3/api-docs/**3. 检查WebSecurityCustomizer是否忽略/swagger-ui/**在authorizeHttpRequests()中放行/v3/api-docs/**在web.ignoring()中忽略/swagger-ui/**登录成功后前端fetch报 CORS 错误浏览器控制台显示Blocked by CORS policySpring Security 默认禁用跨域且未配置CorsConfigurationSource1. 检查SecurityFilterChain是否调用.cors(Customizer.withDefaults())2. 检查是否定义了CorsConfigurationSourceBean3. 检查allowedOrigins是否包含前端地址添加CorsConfigurationSourceBeanallowedOrigins设为[http://localhost:8080]开发或[*]测试AuthenticationManagerBean 未找到启动报错Parameter 0 of method filterChain in com.example.config.SecurityConfig required a bean of type org.springframework.security.authentication.AuthenticationManager that could not be foundSpring Boot 3 中AuthenticationManager不再自动创建需手动暴露1. 检查SecurityConfig是否有Bean方法返回AuthenticationManager2. 检查该方法是否传入AuthenticationConfiguration参数添加Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); }登录后跳转到/login?error输入错误密码页面重定向到/login?errorAuthenticationEntryPoint仍是默认的LoginUrlAuthenticationEntryPoint未替换为HttpStatusEntryPoint1. 检查SecurityFilterChain是否调用.exceptionHandling().authenticationEntryPoint(...)2. 检查是否误用了loginPage(/login.html)这是给 Thymeleaf 用的使用HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)替换默认入口点禁用重定向5.1 独家避坑技巧三个让效率翻倍的实战经验技巧一用curl快速验证 Security 配置比浏览器快十倍浏览器会自动处理重定向、Cookie掩盖问题本质。用curl直接测试原始请求# 测试登录页是否被忽略 curl -I http://localhost:8080/login.html # 应返回 200而非 403 # 测试登录接口是否放行 curl -X POST http://localhost:8080/login -H Content-Type: application/json -d {username:admin,password:123456} # 测试 Swagger 文档是否可访问 curl http://localhost:8080/v3/api-docs-I参数只获取响应头秒出结果。如果curl正常而浏览器不行问题一定在前端代码或浏览器缓存。技巧二启动时打印所有被忽略的路径一眼定位配置遗漏在WebSecurityCustomizer中添加日志Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) - { // 打印所有忽略路径便于调试 System.out.println( Security Ignored Paths ); Arrays.asList( /static/**, /public/**, /resources/**, /webjars/**, /login.html, /login.css, /login.js, /swagger-ui/**, /v3/api-docs/** ).forEach(System.out::println); System.out.println(); web.ignoring().requestMatchers( /static/**, /public/**, /resources/**, /webjars/**, /login.html, /login.css, /login.js, /swagger-ui/**, /v3/api-docs/** ); }; }启动应用控制台会清晰列出所有被忽略的路径。如果某路径不在列表中说明配置未生效。技巧三用Order控制多个SecurityFilterChain的优先级当项目需要多套安全策略如/api/**用 JWT/admin/**用 Session需定义多个SecurityFilterChain。此时必须用Order注解指定顺序Bean Order(1) public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception { http.securityMatcher(/api/**) // 仅匹配 /api/ 开头的请求 .authorizeHttpRequests(authz - authz.anyRequest().authenticated()); return http.build(); } Bean Order(2) public SecurityFilterChain adminFilterChain(HttpSecurity http) throws Exception { http.securityMatcher(/admin/**) // 仅匹配 /admin/ 开头的请求 .authorizeHttpRequests(authz - authz.anyRequest().hasRole(ADMIN)); return http.build(); }Order(1)优先级高于Order(2)确保/api/admin匹配第一个链而非第二个。若顺序颠倒/admin请求可能被错误地交给 API 链处理。最后分享一个小技巧在SecurityFilterChain中添加.headers(headers - headers.frameOptions(FrameOptionsPolicy.SAMEORIGIN))可防止 Clickjacking 攻击这是很多教程忽略的安全细节。
延伸阅读

更多相关文章

2026/10/21 9:13:05

大华摄像头tiktoken鉴权机制深度解析与稳定获取实践

1. 项目概述:这不是在“破解”,而是在理解设备通信的底层逻辑 “记录获取大华摄像头tiktoken流程”——这个标题乍看像技术黑话,实则指向一个非常具体、高频、且长期被低估的工程实践痛点: 如何在不依赖官方SDK或云平台的前提下…

2026/10/21 9:08:03

Hystrix停更后,遗留系统如何安全使用与平滑迁移?

Hystrix这个组件,在微服务容错领域几乎是无人不知:熔断、隔离、降级、超时保护,一度是服务调用链路上的标准配置。但现实很直接——它已经进入维护模式,原厂不再更新功能,修bug也趋于停滞,属于典型的“已停…

2026/10/21 9:08:03

diagram-design:构建可复用的图表设计系统,提升团队协作效率

1. 从“diagram-design”这个标题说起:它到底在解决什么问题第一次看到“diagram-design”这个标题,很多人会下意识觉得它只是“画图”或者“做设计稿”的另一个说法。但真正在项目协作、技术方案评审、产品需求对齐这些场景里摸爬滚打过的人会明白&…

2026/10/21 10:29:01

STM32F103硬件I2C驱动AT24C02 EEPROM读写实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 10:29:01

ESP32舵机控制实战:从PWM原理到多路协同与平滑运动

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 10:29:01

ESP32 纯 C 实现 ONVIF 协议栈:让 NVR 直接发现并预览摄像头

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 10:29:01

M12航插线标准认证全解析:CE/UL与IP防护等级避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 10:29:01

电流型电压互感器:隔离交流电压检测电路设计与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 10:23:55

开源代码审查系统open-code-review:从规则引擎到CI门禁的工程实践

1. 项目整体设计与核心思路拆解作为一个在研发一线待了十多年、经历过无数次"代码审查全靠吼、评审记录靠截图"的老兵,我太清楚代码审查这件事在团队里是什么状态了。早期我们团队做评审,基本就是拉个会议室,对着屏幕一顿讲&#x…

2026/10/21 4:53:08

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/21 0:00:35

交通流仿真实战:IDM跟驰与MOBIL换道模型参数调优与避坑指南

简介:这份资源是面向交通工程学习者与Python开发者的微观交通流仿真项目,核心实现智能驾驶模型(IDM)下的车辆跟驰与换道行为,可用于理解速度、密度与流量之间的动态关系,适合具备Python基础、希望深入交通模…

2026/10/21 0:00:35

揭穿智能体表面顺从:用追踪代码重建任务执行确定性

1. 表面顺从不是智能体的“礼貌”,而是任务执行链路上的隐性断点最近在调试一个跨平台长周期任务调度系统时,我反复遇到一种令人困惑的现象:智能体在用户指令发出后,几乎秒级响应“已收到”“正在处理”“请稍候”,UI上…

2026/10/21 0:00:35

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑