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

Spring Boot Security认证失败:用户账户锁定致403访问被拒

登录接口返回403禁止错误排查

我是Java和Spring Boot应用开发新手,跟着YouTube教程学习。已经实现了注册和登录接口,用Postman测试注册功能正常,用户信息(含加密密码)能存入数据库,但用相同凭证测试登录接口时,出现403请求禁止错误。添加Spring Security调试器后,相关代码及控制台日志如下:

JwtAuthenticationFilter代码:

@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

private final JWTUtil jwtUtil;
private final UserService userService;

@Override
protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest,
                                @NonNull HttpServletResponse httpServletResponse,
                                @NonNull FilterChain filterChain) throws ServletException, IOException {
    final String authHeader = httpServletRequest.getHeader("Authorization");
    final String jwt;
    final String userEmail;
    if(StringUtils.isEmpty(authHeader) || !StringUtils.startsWith(authHeader, "Bearer ")) {
        filterChain.doFilter(httpServletRequest, httpServletResponse);
        return;
    }
    jwt = authHeader.substring(7);
    userEmail = jwtUtil.extractUserName(jwt);
    if(StringUtils.isNoneEmpty(userEmail)
    && SecurityContextHolder.getContext().getAuthentication() == null){
        UserDetails userDetails = userService.userDetailsService().loadUserByUsername(userEmail);
        if(jwtUtil.isTokenValid(jwt, userDetails)){
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
            context.setAuthentication(authToken);
            SecurityContextHolder.setContext(context);
        }
    }
    filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}

WebSecurityConfiguration代码:

@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class WebSecurityConfiguration {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final UserService userService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(request ->
                request.requestMatchers("/api/auth/**").permitAll()
                        .requestMatchers("/api/admin/**").hasAnyAuthority(UserRole.ADMIN.name())
                            .requestMatchers("/api/customer/**").hasAnyAuthority(UserRole.CUSTOMER.name())
                        .anyRequest().authenticated()).sessionManagement(manger ->
                manger.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authenticationProvider(authenticationProviders())
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return httpSecurity.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }
    
    @Bean
    public AuthenticationProvider authenticationProviders() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userService.userDetailsService());
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }
    
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

控制台日志:

2024-03-21T14:58:27.212-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.security.web.FilterChainProxy : Securing POST /api/auth/login
2024-03-21T14:58:27.213-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-03-21T14:58:27.213-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.security.web.FilterChainProxy : Secured POST /api/auth/login
2024-03-21T14:58:27.317-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.s.a.dao.DaoAuthenticationProvider : Failed to authenticate since user account is locked
2024-03-21T14:58:27.320-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-03-21T14:58:27.325-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.security.web.FilterChainProxy : Securing POST /error
2024-03-21T14:58:27.325-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-03-21T14:58:27.327-04:00 DEBUG 14564 --- [nio-9000-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-03-21T15:54:37.576-04:00  INFO 14564 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'

问题原因与解决步骤

从控制台日志的Failed to authenticate since user account is locked可以明确:用户账户被锁定,导致登录验证失败返回403。

解决步骤:

  • 检查用户实体类,确认accountNonLocked字段在注册时是否被设置为true。Spring Security默认要求用户账户未锁定才能通过认证。
  • 若使用JPA实体,修改注册逻辑,确保初始化正确的用户状态:
    // 注册时设置账户状态
    user.setAccountNonLocked(true);
    user.setEnabled(true);
    user.setAccountNonExpired(true);
    user.setCredentialsNonExpired(true);
    
  • 若数据库中已有被锁定的用户,直接修改对应记录的account_non_locked字段为1(或true,取决于字段类型)。
  • 检查UserDetails实现类,确保isAccountNonLocked()方法返回正确的用户状态值。

内容的提问来源于stack exchange,提问作者Madmax7

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:52:33