You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 18:35:58