Spring Security FilterChain为何差异化处理@Controller与@RestController请求?
问题原因分析与解决方案
核心原因
当你使用@Controller时,返回的"home.html"是视图名称,Spring MVC会触发内部转发(forward)去查找对应的视图资源;而@RestController是@Controller + @ResponseBody的组合,返回的字符串会直接作为响应体返回,不会触发转发。
Spring Security的过滤器链默认会拦截所有请求,包括内部转发请求:
- 用
@RestController时,请求只走一次过滤器链,匹配到/home的permitAll规则,直接放行,返回字符串。 - 用
@Controller时,初始请求/home被放行,但后续转发到视图资源的路径(比如/templates/home.html,取决于你的视图解析器配置)不在permitAll列表里,过滤器链会拦截这个转发请求,触发重定向登录。
解决办法
方法1:放行视图资源的路径
在Security配置中添加视图资源所在目录的permitAll规则,比如视图文件放在/templates/或/static/下:
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(authorize -> { authorize.requestMatchers("/", "/home", "/templates/**", "/static/**").permitAll(); authorize.anyRequest().authenticated(); }) .formLogin(withDefaults()) .oauth2Login(withDefaults()) .build(); }
方法2:给方法添加@ResponseBody
如果不需要视图解析,只想返回字符串,直接在@Controller的方法上加上@ResponseBody,效果和@RestController一致:
@GetMapping("home") @ResponseBody public String home(){ return "home.html"; }
方法3:配置Security不拦截内部转发
通过指定DispatcherType排除转发请求的拦截:
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { return http .authorizeHttpRequests(authorize -> { // 放行所有转发请求 authorize.requestMatchers(DispatcherType.FORWARD, "/**").permitAll(); authorize.requestMatchers("/", "/home").permitAll(); authorize.anyRequest().authenticated(); }) .formLogin(withDefaults()) .oauth2Login(withDefaults()) .build(); }
内容的提问来源于stack exchange,提问作者user28811040
相关产品推荐
相关产品推荐

