SpringBoot配置Spring Security后调用接口出现401权限错误求助
Spring Security权限验证异常排查
问题概述
搭建个人项目时遇到Spring Security权限问题:
- 已完成Security配置,应用流程看似正常,但使用正确凭据调用保存俱乐部的接口时仍返回401错误
- 使用
@Secured注解时出现异常,无权限用户也能访问授权端点
相关代码
Security配置类
@Configuration @EnableMethodSecurity public class SecurityConfig { @Autowired private UserDetailsServiceImpl userDetailServices; @Autowired private EntryPoint authEntryPoint; @Bean public securityFilter authFilter() { return new securityFilter(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(userDetailServices); authenticationProvider.setPasswordEncoder(passwordEncoder()); return authenticationProvider; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration auth) throws Exception { return auth.getAuthenticationManager(); } @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity .csrf(csrf->csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers( "/", "/api/v1/auth/signin", "/api/v1/auth/signup", "/api/v1/auth/**", "/v3/api-docs/**", "/v3/api-docs.yaml", "/swagger-ui/**", "/swagger-ui.html").permitAll() .requestMatchers(HttpMethod.OPTIONS,"/**").permitAll() .anyRequest().authenticated() ) .exceptionHandling(exception -> exception.authenticationEntryPoint(authEntryPoint)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authenticationProvider(authenticationProvider()) .addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class); return httpSecurity.build(); } }
Controller代码
@PostMapping("/new") @PreAuthorize("hasRole('MODERATOR')") public ResponseEntity<?> saveClub(@RequestBody ClubDto clubDto) { clubsService.saveClub(clubDto); Map<String, String> resp = new HashMap<>(); resp.put("Message", "Club Registred Succesfully"); return ResponseEntity.ok(resp); }
Service实现代码
@Override public void saveClub(ClubDto clubDto) { Clubs clubs = new Clubs(); clubs.setTitle(clubDto.getClubName()); clubs.setContent(clubDto.getContent()); clubs.setCreatedOn(LocalDate.now()); String userContext= (String)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); UserEntity user =userRepository.findByUsername(userContext). orElseThrow(()->new ResousrceNotFoundException("User not found")); clubs.getUserEntitySet().add(user); clubRepository.save(clubs); }
错误日志
开启Spring Security日志后得到如下错误:
Failed to authorize ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity com.example.clubsapi.controller.ClubController.saveClub(com.example.clubsapi.dto.ClubDto); target is of class [com.example.clubsapi.controller.ClubController] with authorization manager org.springframework.security.config.annotation.method.configuration.DeferringObservationAuthorizationManager@1137605f and decision ExpressionAuthorizationDecision [granted=false, expressionAttribute=hasRole('MODERATOR')]
排查与解决方向
检查自定义
securityFilter实现:该过滤器负责解析请求中的认证信息并将Authentication对象存入SecurityContextHolder。需确认:- 是否正确解析token中的用户权限信息
- 创建Authentication对象(如UsernamePasswordAuthenticationToken)时,是否传入了完整的
GrantedAuthority集合,而非仅用户名 - 是否在过滤器中执行了
SecurityContextHolder.getContext().setAuthentication(auth)操作
验证UserDetailsServiceImpl的权限封装:
loadUserByUsername方法返回的UserDetails对象,需包含正确的权限信息。注意hasRole('MODERATOR')会自动添加ROLE_前缀,若数据库中存储的角色是MODERATOR,需封装为new SimpleGrantedAuthority("ROLE_MODERATOR");若不想加前缀,可改用hasAuthority('MODERATOR')
修正@EnableMethodSecurity配置:若要使用
@Secured注解,需显式开启支持:@EnableMethodSecurity(securedEnabled = true)默认配置下
securedEnabled为false,会导致@Secured注解不生效检查SecurityContext传递:由于配置了
SessionCreationPolicy.STATELESS,需确保每个请求的自定义过滤器都正确设置SecurityContext,避免上下文丢失导致权限验证失败修复Service中的Principal获取逻辑:当前代码中
getPrincipal()返回String类型用户名,说明Authentication对象未封装完整的UserDetails信息。建议创建Authentication时传入UserDetails实例,而非仅用户名,这样能直接获取用户权限等信息
内容的提问来源于stack exchange,提问作者Santosh
相关产品推荐
相关产品推荐

