Spring Security配置异常:未授权跳转登录及403错误排查
核心问题分析
1. 根路径/被拦截触发登录表单
你在HomeController中使用@Controller注解,方法返回的<h1>Welcome</h1>会被Spring MVC当作视图名称去查找对应的视图模板(如Thymeleaf、JSP等),但项目中未配置视图解析器和对应视图文件,导致请求转发到错误页面(如/error),而Spring Security默认拦截错误页面,因此触发登录表单。
2. 登录后访问/admin或/user返回403
Spring Security的hasRole("ADMIN")和hasRole("USER")方法会自动在角色名称前添加ROLE_前缀进行权限匹配,但你的User实体中getAuthorities()方法直接将角色名称(如"ADMIN")封装为SimpleGrantedAuthority,导致实际权限为ADMIN,而Spring Security期望的是ROLE_ADMIN,权限不匹配从而返回403。
解决方案
针对根路径拦截问题
将HomeController的@Controller改为@RestController,或者在每个返回字符串的方法上添加@ResponseBody,让返回的字符串直接作为HTTP响应体,而非视图名称:
@RestController // 替换原@Controller public class HomeController { @GetMapping("/") public String home(){ return ("<h1>Welcome</h1>"); } @GetMapping("/user") public String homeUser(){ return ("<h1>Welcome user </h1>"); } @GetMapping("/admin") public String homeAdmin(){ return ("<h1>Welcome admin </h1>"); } }
针对403权限不匹配问题
方案一:修改权限前缀(推荐)
修改User实体中的getAuthorities()方法,在角色名称前添加ROLE_前缀:
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return roles.stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName())) .collect(Collectors.toList()); }
方案二:修改权限匹配规则
如果你不想修改权限前缀,可以将Security配置中的hasRole改为hasAuthority,直接匹配原始角色名称:
http.authorizeHttpRequests((auth)-> { auth.requestMatchers("/").permitAll(); auth.requestMatchers("/admin").hasAuthority("ADMIN"); // 替换hasRole为hasAuthority auth.requestMatchers("/user").hasAuthority("USER"); auth.anyRequest().authenticated(); // 建议添加,明确其他请求需要认证 })
额外优化建议
在SecurityFilterChain配置中添加auth.anyRequest().authenticated(),明确除已配置的放行路径外,其他所有请求都需要认证,避免规则模糊:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http.csrf(AbstractHttpConfigurer::disable); http.authorizeHttpRequests((auth)-> { auth.requestMatchers("/").permitAll(); auth.requestMatchers("/admin").hasRole("ADMIN"); auth.requestMatchers("/user").hasRole("USER"); auth.anyRequest().authenticated(); // 添加此行 }) .userDetailsService(userService) .formLogin(Customizer.withDefaults()); return http.build(); }
验证步骤
- 修改代码后重启应用
- 访问
http://localhost:8081/,应直接看到<h1>Welcome</h1> - 访问
http://localhost:8081/user,触发登录表单后使用user/user登录,应看到用户欢迎信息 - 访问
http://localhost:8081/admin,触发登录表单后使用admin/admin登录,应看到管理员欢迎信息
内容的提问来源于stack exchange,提问作者Lenroc 777

