news 2026/9/8 15:40:36

Spring Security 6配置实战:从SecurityFilterChain到组件化迁移指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Security 6配置实战:从SecurityFilterChain到组件化迁移指南

Spring Security 新版本配置这几年让不少从 Spring Boot 2 时代过来的开发者在升级时栽了跟头。以前老项目里最常见的写法,就是让配置类继承WebSecurityConfigurerAdapter,然后重写configure(HttpSecurity http),里面用antMatchers(...).permitAll()一把梭;从 Spring Security 5.7 开始这种写法就不断告警,到 Spring Security 6 直接移除。你现在打开新项目会发现,整个配置思路已经换成了组件化写法:不再有 Adapter,不再有.and()链式拼接,而是通过HttpSecurity上的方法组合出一个SecurityFilterChainBean。这篇内容就是针对 Spring Security 新版本配置的一线实操总结,包含我升级过程中踩过的坑、调整过的方案,以及现在最常用的配置骨架。适合正准备从旧版迁移,或者刚接触 Spring Boot 3 + Spring Security 6 的朋友参考,读完拿去做项目改造基本够用。

1. 先盘清楚:新版本配置到底改了什么

1.1 从 WebSecurityConfigurerAdapter 到组件化配置

先说一个很多人没想明白的问题:为什么 Spring Security 一定要把WebSecurityConfigurerAdapter干掉?

旧版里,一次只允许一个配置适配器生效。项目稍大一点,你想对不同的 URL 目录应用不同规则,只能靠多个WebSecurityConfigurerAdapter@Order去控制。用起来很绕,而且扩展点都藏在重写方法里,新手看半天也不知道哪个方法被哪个框架回调了。新版本的做法是把“适配器”这个概念彻底去掉,改成直接暴露SecurityFilterChain和过滤器链注册机制。

本质上,你现在要做的事情和以前是一样的:核心还是构建一条过滤器链。只是注册方式从“继承 + 重写”变成了“声明 Bean + 方法调用”。下面是一份最精简的新版核心配置,你对比一下旧写法就能看出差别:

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated() ) .formLogin(Customizer.withDefaults()); return http.build(); } }

注意三点:

  • 配置类不需要继承任何类,@Configuration加上一个返回SecurityFilterChain@Bean方法就行。
  • authorizeHttpRequests替代了旧的authorizeRequests,里面用的是requestMatchers,旧版antMatchersmvcMatchers已经淡出。
  • 方法内部直接用 lambda 配置,不需要.and()来回切换上下文。

1.2 为什么.and()没了,以及 Lambda DSL 的好处

很多旧代码里能看到一大串.and().and().and()结构,例如:

http.authorizeRequests() .antMatchers("/public/**").permitAll() .and() .formLogin() .loginPage("/login") .and() .logout() .logoutUrl("/logout");

这种写法的问题在于:.and()只是把对象切回HttpSecurity,一旦中间某一步传错了配置器,编译器基本帮不上忙。新版本的 Lambda DSL 会让每个配置模块的上下文保持清晰,配置formLogincsrfsessionManagement时各自独立成块,代码可读性高了一个量级,IDE 自动补全也更友好。

不过这里要提醒一句:网上不少老教程虽然标题是“新版本”,代码却还停留在.and()时代,甚至把authorizeRequestsauthorizeHttpRequests混在一起写。这种代码在新版里会直接编译失败,提示找不到antMatchers()。我看到太多帖子把这种情况归结为“Spring Security 太难了”,其实只是 API 换了个位置。

1.3 默认策略收紧:CSRF、CORS、Session 策略的变化

新版本除了 API 换了写法,还有一个容易忽略的点:默认策略比旧版严格了很多。

  • CSRF(跨站请求伪造防护)默认开启。如果你的服务是前后端分离的无状态接口,且不使用浏览器 Cookie 做身份凭证,就需要显式关闭 CSRF,否则所有 POST、PUT、DELETE 请求都会被拦截。
  • 默认登录页/login依然自带,但如果你希望做完全自定义的 JSON 登录,需要把默认的formLogin关掉并添加自己的认证过滤器。
  • 在 Spring Security 6 里,对无状态场景的推荐方式是配置SessionCreationPolicy.STATELESS,避免框架默认创建 Session。

这里的核心认知是:新版本希望开发者在写每一行配置前,主动想清楚自己的应用形态是“传统服务端渲染页面”还是“前后端分离接口服务”。如果是前者,很多默认行为可以直接用;如果是后者,你要显式关掉 CSRF、配置 CORS,并且不要让框架维护 Session。

我在项目里给团队定了个很简单的小口诀:csrf要看凭证存放位置,session要看服务端要不要维护状态,cors要看浏览器接口是否跨域。这三个前提搞不清楚,配置文档抄得再多也会埋坑。

2. 搭建新版核心配置:一个可以落地的 SecurityFilterChain

2.1 最简配置怎么写才安全

网上能找到的新版“最简配置”,基本上都是这种风格:

http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .anyRequest().permitAll());

这段代码的问题是:它把认证和授权全关了,算什么安全配置?适合新建一个临时测试工程第一次确认 Spring Boot 能跑起来,但如果你直接把它当成项目骨架,那还不如不加 Security 依赖。

我建议的最小可用配置是这样的:保留密码加密校验能力,默认所有请求都必须经过认证,只放开健康检查和登录入口,然后根据实际需求逐步加规则。这样配置上线后即使忘了某个细节,没有一个大口子直接暴露在外面。

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/health", "/error", "/api/auth/login").permitAll() .anyRequest().authenticated() ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .httpBasic(Customizer.withDefaults()); return http.build(); } }

把一个请求“先全拦住,再按需放行”作为底线,比一开始就permitAll()一大片安全得多。后面要接 Swagger 文档、静态资源或者前端页面,再单独把对应路径加进permitAll列表里,风险就可控了。

2.2 内存用户与密码解析器组合

没有接数据库之前,最快的用户配置方式是InMemoryUserDetailsManager。但这里有几个细节必须注意。

首先是密码绝对不能存明文。Spring Security 新版本里默认的PasswordEncoder是一个DelegatingPasswordEncoder,它会把密码按{id}密文格式存储,例如{bcrypt}$2a$10$xxxx。你在代码里创建内存用户时,一定要先调用passwordEncoder.encode("明文")

@Bean UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { UserDetails admin = User.builder() .username("admin") .password(passwordEncoder.encode("Admin@123")) .roles("ADMIN", "USER") .build(); UserDetails viewer = User.builder() .username("viewer") .password(passwordEncoder.encode("Viewer@123")) .roles("USER") .build(); return new InMemoryUserDetailsManager(admin, viewer); } @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }

这里有一个很常见的报错:你只自定义了UserDetailsService,但忘了声明PasswordEncoder,启动时会报There is no PasswordEncoder mapped for the id "null"。这个问题的根源是默认的密码解析器拿到一个没有{id}前缀的密码,不敢确定该用哪种算法去解密,所以直接报错。

新版本里我建议统一用一个BCryptPasswordEncoder作为全局密码编码器,配合DelegatingPasswordEncoder的灵活性。如果你有旧系统的MD5SHA-256等历史密码需要兼容,可以在PasswordEncoderFactories.createDelegatingPasswordEncoder()基础上扩展,但新密码一律用 bcrypt。这样既保证兼容,又不会把新数据存成弱算法。

2.3 基于数据库的真实用户服务

内存用户只适合原型阶段,真实项目还是要接入数据库。新版 Spring Security 里定义一个UserDetailsServiceBean,框架就会在认证流程中自动使用它:

@Service public class DbUserDetailsService implements UserDetailsService { private final UserRepository userRepository; public DbUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("user not found: " + username)); return org.springframework.security.core.userdetails.User.builder() .username(user.getUsername()) .password(user.getPassword()) .roles(user.getRoles().split(",")) .disabled(!user.isEnabled()) .build(); } }

记得把数据库用户表里的password字段存成加密后的结果,不是明文。很多团队喜欢把roles字段用逗号分隔拼在一个字段里,这种方式在用户量不大、角色关系不复杂的系统里确实省事,但查询时要注意做权限变更后的缓存刷新,否则用户改了角色要等登录态过期才生效。

如果你需要把“数据库密码校验失败”“用户被锁定”等不同异常区分开处理,可以自定义AuthenticationProvider,在里面注入UserDetailsServicePasswordEncoder。但在大多数场景下,DaoAuthenticationProvider已经内置了这些功能,直接让框架自动装配即可。

从配置角度来说,新版代码里并不需要手动写一堆 Provider 逻辑。只有当你需要接入第三方登录、短信验证码或者动态 token 时,才需要自定义AuthenticationProvider并注册到AuthenticationManager中。

2.4 多过滤器链:让管理后台和用户接口走不同规则

这是新版本里值得充分利用的能力:你可以声明多个SecurityFilterChainBean,并通过@Order控制优先级。旧版里要实现“同一个应用,用户端接口和管理后台接口使用不同安全规则”,要借助多个 Adapter 的 Order,很容易踩坑。新版里干脆把每条过滤器链的匹配规则直接写在requestMatchers上:

@Configuration @EnableWebSecurity public class MultiChainSecurityConfig { @Bean @Order(1) SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/admin/**") .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/admin/login").permitAll() .anyRequest().hasRole("ADMIN") ) .formLogin(Customizer.withDefaults()); return http.build(); } @Bean @Order(2) SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception { http .securityMatcher("/api/**") .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/login", "/api/public/**").permitAll() .anyRequest().authenticated() ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .httpBasic(Customizer.withDefaults()); return http.build(); } }

这里最容易犯的错误是:securityMatcher的作用范围没有覆盖所有请求,导致某些路径落到了最底层的默认过滤器链上,结果被 401 或 403 拦下来。如果你同时声明了多条过滤器链,最好再加一个兜底的默认链,确保所有未匹配的请求有明确的安全策略。我在生产项目里就亲眼看过一次这种配置事故:用户端接口和管理端接口分了两条链,结果OPTIONS预检请求没匹配到任何配置,被默认规则直接挡掉,前端控制台全是跨域报错,排查半天才定位到规则重叠的问题。

3. 新版本实际操作过程:登录、鉴权、OAuth2 那些容易踩坑的地方

3.1 前后端分离下的 JSON 登录接口怎么接

很多团队从旧版过渡时问得最多的一句话是:能不能不用默认的表单登录页,自己写一个/auth/login接口,接收 JSON 用户名密码?

默认的UsernamePasswordAuthenticationFilter只会从请求参数里获取用户名和密码,不会解析 JSON。所以你需要做两件事:

  • 关闭默认的表单登录过滤器。
  • 在过滤器链合适的位置,添加一个自定义 JSON 登录过滤器,或者直接绕过过滤器链,在业务 Controller 里手动调用AuthenticationManager

我更推荐后一种“手动认证”方案。在 Controller 里注入AuthenticationManager,写一个登录方法:

@PostMapping("/auth/login") public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(request.username(), request.password()) ); SecurityContextHolder.getContext().setAuthentication(authentication); // 然后按自己项目的规范生成 token 返回给前端 }

这样的好处是登录逻辑完全可控,路径可以自己定义,返回结构也能统一。得到Authentication对象后,因为是无状态应用,通常会把用户信息和过期时间封装成 Token。配置方面只需要确保/auth/login路径被permitAll放行,并且框架不会因为没经过UsernamePasswordAuthenticationFilter而拒绝你的业务请求。

一个小细节:手动认证时,如果没有调用SecurityContextHolder.getContext().setAuthentication(...),后续一旦走到任何依赖当前登录用户的方法级权限处理,都会拿不到用户信息。即使你是用 Token 方案,也应该在校验 Token 后设置一次 SecurityContext,保证@AuthenticationPrincipal等注解能正常工作。

3.2 方法级鉴权:@PreAuthorize 和 @EnableMethodSecurity 怎么配

新版 Spring Security 中,方法级安全已经独立成一个专门的注解配置,类上要加@EnableMethodSecurity,而不是旧的@EnableGlobalMethodSecurity。这个细节很容易被忽略,因为很多旧教程标题写着 Spring Security 6,代码里却还在用@EnableGlobalMethodSecurity,跑起来也不报错,但方法上的@PreAuthorize就是不生效。

正确姿势是在通过@Configuration配置的类上加注解:

@Configuration @EnableWebSecurity @EnableMethodSecurity public class SecurityConfig { // ... }

之后在 Controller 或 Service 方法上使用:

@PreAuthorize("hasRole('ADMIN')") @GetMapping("/admin/users") public List<UserVO> listUsers() { return userService.listAll(); } @PreAuthorize("hasAuthority('user:update')") @PutMapping("/users/{id}") public void updateUser(@PathVariable Long id, @RequestBody UserUpdateRequest request) { userService.update(id, request); }

区分hasRolehasAuthority也很重要。如果你在用户服务里给用户设置的是roles("ADMIN"),那么框架会默认给它加ROLE_前缀,方法注解里就要写hasRole("ADMIN")。如果你设置的是authorities("user:update")这种细粒度权限码,就要写hasAuthority("user:update")。两者混放在实际项目里非常常见,运维排查权限问题时,很多“为什么用户明明有权限但接口返回 403”的案例,最后都查到是角色前缀没对上。

@EnableMethodSecurity里还有几个可以开关的选项,比如jsr250Enabled = true可以启用@RolesAllowedprePostEnabled默认也是开启的。日常项目直接用默认配置就好,不用刻意把每个注解体系都打开。

3.3 Spring Boot 3 整合 OAuth2 资源服务器时,别再纠结 hasScope

热词里提到“spring security oauth2 没有 hasScope 方法了吗”,这个问题我在很多群里被问过。其实你去翻官方文档或源码会发现,oauth2ResourceServer()配置器上并没有一个叫hasScope的全局方法。很多老文章里的写法是从旧的授权服务器扩展点直接抄过来的,到了新版本自然编译不过。

正确做法是:JWT 方式接入资源服务器时,在authorizeHttpRequests里判断 Scope。

http.oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(jwtAuthenticationConverter()) )) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/orders/**").hasAuthority("SCOPE_order:read") .anyRequest().authenticated() );

因为在 Spring Security 的默认实现中,从 JWT 的scopescp声明解析出来的权限,会以SCOPE_作为前缀变成一个个 authority。你在授权规则里直接用hasAuthority("SCOPE_order:read")判断即可。看到SCOPE_前缀就明白,这是从 JWT Scope 映射出来的权限,而不是数据库里给用户单独配置的权限。

如果你的授权服务器在 JWT 里存放的是自定义字段,比如"roles": ["admin"],那你需要提供一个JwtAuthenticationConverter的 Bean,把这个字段解析成ROLE_admin权限,否则 Spring Security 默认只会处理scope/scp字段。之前有朋友接到一个第三方单点登录系统,JWT 里权限字段叫authorities,结果在网关层全部 403,最后就是自定义了一个转换器才解决。**

自定义转换器的实现很简单:

@Bean JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter(); converter.setJwtClaimName("authorities"); converter.setAuthorityPrefix("ROLE_"); JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(converter); return jwtAuthenticationConverter; }

这段代码的作用就是把 JWT 中名为authorities的声明取出,并统一加上ROLE_前缀。这样你在@PreAuthorize("hasRole('ADMIN')")里写的角色才能匹配上。

3.4 登录状态与跨域:CORS 到底该配在哪一端

前后端分离开发时,跨域问题经常被丢给后端。新版 Spring Security 里,如果你只依赖 Spring MVC 的@CrossOrigin或全局CorsFilter,同时又用了 Spring Security,有时候 CORS 会被过滤器链的优先级挡住。建议在 Security 配置里统一管理:

@Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 其他配置 return http.build(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOriginPatterns(List.of("http://localhost:8080", "https://*.example.com")); config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(List.of("*")); config.setAllowCredentials(true); config.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; }

这段配置里我用了setAllowedOriginPatterns而不是setAllowedOrigins。原因是当allowCredentials为 true 时,setAllowedOrigins不支持通配符*,如果你允许前端带上 Cookie 或 Authorization 头,就必须用精确源或者AllowedOriginPatterns。很多初学者会在这里遇到“貌似 CORS 配置了但还是报跨域错误”的情况,基本都是因为这个细节。

跨域预检请求OPTIONS是由 CORS 机制处理的,配置了上面的CorsConfigurationSource后,Spring Security 会正确放行预检,不需要你在authorizeHttpRequests里单独把OPTIONS全部permitAll。如果你看到接口单独用 Postman 调没问题,浏览器一调就挂,十有八九是 CORS 配置没生效或没走到 Security 的 CORS 过滤器前,而不是后端业务接口拒绝跨域。

4. 新版本配置实战排坑:我至少遇到过这些异常

4.1 启动 500 报错:无法获取 AuthenticationManager

在 Spring Security 6 中,如果你在 Controller 里直接注入AuthenticationManager,而项目里又没有显式声明这个 Bean,启动可能会失败。常见报错提示找不到AuthenticationManager

解决办法是在配置类中显式暴露它:

@Configuration public class AuthManagerConfig { private final AuthenticationConfiguration authenticationConfiguration; public AuthManagerConfig(AuthenticationConfiguration authenticationConfiguration) { this.authenticationConfiguration = authenticationConfiguration; } @Bean AuthenticationManager authenticationManager() throws Exception { return authenticationConfiguration.getAuthenticationManager(); } }

AuthenticationConfiguration会自动感知你在项目中配置的UserDetailsServicePasswordEncoder以及自定义的AuthenticationProvider,最终生成的AuthenticationManager就能用于手动认证。不要自己在配置类里 new 一个ProviderManager,那样反而容易漏掉全局的 UserDetailsService。

4.2 登录成功后一直拿不到用户信息

经常遇到的现象是:调用登录接口成功,Token 也正常返回了,但下一个接口把 Token 带过去,后端处理时Authentication为 null。

这种情况一般不是过滤器链写错,而是没有在每次请求到达 Controller 之前,根据 Token 还原登录态。你需要一个自定义过滤器,放在UsernamePasswordAuthenticationFilter之前读取 Token:

@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = resolveToken(request); if (token != null && SecurityContextHolder.getContext().getAuthentication() == null) { // 这里解析 token,得到用户身份 // 构造 UsernamePasswordAuthenticationToken,并 setAuthenticated(true) SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } }

然后在 Security 配置中注册:

http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

很多项目在接入 Token 登录时,登录接口自己写了一套签发逻辑,却漏掉了“每次请求都解析 Token 并恢复 SecurityContext”这个环节。只要漏了这一层,后续所有靠 SecurityContext 判断用户身份的逻辑全部失效。记住:自动登录状态恢复的本质,就是在过滤器里替框架把“用户凭证”找回来。

4.3 授权规则顺序导致的 403

authorizeHttpRequests里的规则是按从上到下顺序匹配的,先匹配到的规则先生效。常见的错误是把anyRequest().authenticated()写在中间,结果后面的permitAll()全部不生效。

比较稳妥的顺序是:先放行完全公开的接口和静态资源,再做方法级之外的粗粒度角色判断,最后用anyRequest()兜底。

http.authorizeHttpRequests(auth -> auth .requestMatchers("/public/**", "/assets/**", "/error").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() );

我一直跟团队强调,授权规则不要写得太多太细。系统复杂到一定规模后,把所有权限判断都堆在安全配置类里面,很难维护。建议在配置类里只做“公共接口放行”和“大块 URL 目录的角色隔离”,真正细粒度的数据权限放到 Service 层用@PreAuthorize去处理,这样定位问题会快很多。

4.4 常用问题与排查路径速查

现象优先排查点常见原因
接口返回 401Token 过滤器是否执行、permitAll路径是否正确Token 解析失败或未放行公开接口
接口返回 403用户权限前缀、角色是否匹配没有ROLE_前缀,或规则顺序不对
登录接口一直走默认登录页是否关闭了formLogin自定义 JSON 登录还需关闭默认表单
密码错误但没提示PasswordEncoder是否统一多个密码编码器或存了明文
跨域请求报错CORS 配置、OPTIONS预检没有走 Security 的 CorsConfigurationSource
SecurityContext 为空过滤器顺序自定义过滤器没有注册或顺序颠倒
@PreAuthorize不生效配置类是否加了@EnableMethodSecurity使用了旧注解

每次排查这些问题时,我习惯先看一眼请求到底经过了哪些过滤器。可以在日志级别里把org.springframework.security调成DEBUG,过滤链的执行情况会被完整打印出来。实际追踪一遍过滤器执行顺序,比自己凭空猜配置位置高效得多。我处理的绝大多数 Security 疑难杂症,都是靠这个手段定位到具体过滤器节点的。

5. 最后说几句配置思路上的体会

WebSecurityConfigurerAdapterSecurityFilterChain,表面上是换了一套 API,背后其实是 Spring Security 团队推动了很多年的设计目标:让安全配置显式化、模块化,避免代码被隐藏的继承逻辑控制。

我在实际项目里最深的体会是:配置类不要写成一个巨无霸。无论SecurityFilterChain还是各种Bean,都按模块拆开,比如密码策略一个类、CORS 一个类、OAuth2 一个类。新版组件化配置本身就适合这种做法,但很多人还是习惯把代码全堆在一个SecurityConfig里,半年后没人能改得动。

另一个很实用的做法是:每次升级 Spring Boot 版本前,先用 Spring Security 官方迁移文档对照一遍自己项目里用到的 API,因为很多“新版本不再支持”的提示并不会在启动时立刻报错,而是跑到某个接口时才出现诡异问题。依赖管理尽量用 Spring Boot 的 BOM 统一控制版本,不要单独指定某个 Spring Security 版本跟 Boot 大版本错位。

最后分享一个小技巧:如果你在用 Spring Boot 3.x,并且项目里引入了@EnableWebSecurity,但没有任何SecurityFilterChainBean,系统会使用默认的BackButton...这类自动兜底配置。很多人想先快速跑通业务,就随手加一行@EnableWebSecurity,结果所有请求都被默认认证拦住了,还以为是自己路径写错。实际上,你不做任何 Security 配置时 Spring Boot 也会给应用加上默认账号密码,地址就在启动日志里自动生成的那个Using generated security password。这个默认账号密码不是随便生成的,而是框架给你留的最后一道保险。搞清楚这套逻辑,你对新版本配置的掌握就能比网上大多数照抄教程的开发者更扎实。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 15:38:38

SSD写放大优化策略要统一标准了吗?

1. 引言&#xff1a;为什么写放大问题重新回到舞台中央过去十年&#xff0c;闪存技术发展的主旋律是“更快、更密、更便宜”。容量从SLC一路演进到MLC、TLC、QLC&#xff0c;接口从SATA升级到PCIe 4.0、5.0甚至6.0&#xff0c;随机读写性能提升了几个数量级。然而有一只看不见的…

作者头像 李华
网站建设 2026/9/8 15:38:36

从代码补全到研发流水线:MonkeyCode如何将AI嵌入企业开发全流程

放下“代码补全”这个名词&#xff0c;我想聊聊MonkeyCode真正在解决的事情。如果你做过AI编程工具的企业级落地&#xff0c;应该会有同样的感受&#xff1a;给团队装一个能“自动补全”的IDE插件&#xff0c;和把AI真正“焊”进研发流程&#xff0c;中间隔着一条巨大的鸿沟。补…

作者头像 李华
网站建设 2026/9/8 15:38:28

IEEE 9节点系统接入DFIG风电场仿真搭建全攻略

做电力系统仿真这几年&#xff0c;我越来越觉得IEEE 9节点系统是个“又爱又恨”的东西。爱它&#xff0c;是因为它足够简单&#xff0c;三机九节点&#xff0c;拓扑清晰&#xff0c;参数公开&#xff0c;几乎是每个做电力系统稳定分析的人绕不开的入门benchmark&#xff1b;恨它…

作者头像 李华
网站建设 2026/9/8 15:36:57

C# 图像实现亚像素精度:使用OpenCvSharp实现亚像素精度的定位

C# 图像实现亚像素精度&#xff1a;使用OpenCvSharp实现亚像素精度的定位客户说精度不够&#xff0c;我把定位从像素级干到了亚像素&#xff0c;误差从0.8mm压到0.02mm一、亚像素到底在干什么&#xff1f;二、亚像素角点定位CornerSubPix&#xff08;最常用&#xff09;三、亚像…

作者头像 李华
网站建设 2026/9/8 15:36:05

网络调试助手20200711_v2.2:从zip解压到TCP/UDP联调实战

简介&#xff1a;一款基于QT框架打造的TCP网络调试工具&#xff0c;面向QT开发者、网络工程师及嵌入式调试人员&#xff0c;通过模拟客户端与服务端交互&#xff0c;帮助定位连接建立、数据收发、连接关闭等环节的通信问题。压缩包内含37个文件&#xff0c;以2个cpp源文件、1个…

作者头像 李华