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

Java API安全过滤器空指针异常:UserRepository注入为空

问题:SecurityFilter中UserRepository空指针异常

java.lang.NullPointerException: Cannot invoke "school.pachecos.api.users.UserRepository.findByEmail(String)" because "this.user_repository" is null

相关代码

SecurityFilter

@Component
public class SecurityFilter extends OncePerRequestFilter {

    @Autowired
    TokenService token_service = new TokenService();
    @Autowired
    private UserRepository user_repository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filter_chain) throws ServletException, IOException {
        String token = getToken(request);
        if(token != null){
            String token_subject = token_service.getTokenSubject(token);
            UserDetails user_entity = user_repository.findByEmail(token_subject);
            Authentication authentication = new UsernamePasswordAuthenticationToken(user_entity, null, user_entity.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filter_chain.doFilter(request, response);
    }

    private String getToken(HttpServletRequest request){
        String token = request.getHeader("Authorization");
        if(token == null){
            return null;
        }
        return token.replace("Bearer", "");
    }

}

SecurityConfigurations

@Configuration
@EnableWebSecurity
public class SecurityConfigurations {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(http_request -> http_request
                .requestMatchers("/auth/login").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(new SecurityFilter(), UsernamePasswordAuthenticationFilter.class)
            .build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration auth_config) throws Exception {
        return auth_config.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

TokenService

@Service
public class TokenService {

    private final String secret = "b0eMdsHE5jKDW9RsjuC5VrF8BT7P2oHubObbdBvaVbfzlXgKftxQ2WrZfX4RtU04";
    private final String ISSUER = "API Pacheco's School";

    public String createToken(UserEntity user){
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withIssuer(ISSUER)
                    .withExpiresAt(getExpiresAt())
                    .withSubject(user.getUsername())
                    .sign(algorithm);
        } catch (JWTCreationException exception){
            return null;
        }
    }

    private Instant getExpiresAt(){
        return LocalDateTime.now().plusDays(1).toInstant(ZoneOffset.of("-03:00"));
    }

    public String getTokenSubject(String token){
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            return JWT.require(algorithm)
                    .withIssuer(ISSUER)
                    .build()
                    .verify(token)
                    .getSubject();
        } catch (JWTVerificationException exception){
            return null;
        }
    }
}

UserRepository

public interface UserRepository extends JpaRepository<UserEntity, Long> {

    @Query(value = "SELECT u FROM UserEntity u WHERE " +
        "u.name LIKE CONCAT('%', :name, '%') " +
        "OR u.birth_date = :date " +
        "OR u.email LIKE CONCAT('%', :email, '%') " +
        "OR cellphone LIKE CONCAT('%', :cellphone, '%') "
    )
    Collection<UserEntity> searchUsers(String name, LocalDate date, String email, String cellphone);

    UserDetails findByEmail(String email);
}

用户疑问:此前TokenService也出现过类似空指针问题,我通过new实例化解决了,但UserRepository无法这么做,请问该如何解决?


解决方法

核心原因

你在SecurityConfigurations里手动new SecurityFilter()创建实例,这个对象不属于Spring容器管理,导致@Autowired注解完全失效,UserRepository和TokenService都无法被注入,自然会出现空指针。

具体修正步骤

  1. 修复TokenService的注入方式
    删掉SecurityFilter中TokenService的手动实例化,让Spring负责注入:

    @Autowired
    private TokenService token_service;
    
  2. 让Spring管理SecurityFilter实例
    在SecurityConfigurations中通过构造方法注入SecurityFilter,不要手动new:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfigurations {
    
        private final SecurityFilter securityFilter;
    
        // 构造方法注入Spring容器管理的SecurityFilter实例
        public SecurityConfigurations(SecurityFilter securityFilter) {
            this.securityFilter = securityFilter;
        }
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            return http
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(http_request -> http_request
                    .requestMatchers("/auth/login").permitAll()
                    .anyRequest().authenticated()
                )
                .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 使用注入的实例,而非手动new
                .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
        }
    
        // 其余Bean方法保持不变
        @Bean
        public AuthenticationManager authenticationManager(AuthenticationConfiguration auth_config) throws Exception {
            return auth_config.getAuthenticationManager();
        }
    
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
    }
    
  3. 可选:改用构造方法注入(推荐)
    为了符合Spring最佳实践,把SecurityFilter的字段注入改成构造方法注入,避免字段注入的弊端:

    @Component
    public class SecurityFilter extends OncePerRequestFilter {
    
        private final TokenService tokenService;
        private final UserRepository userRepository;
    
        // 构造方法注入依赖
        public SecurityFilter(TokenService tokenService, UserRepository userRepository) {
            this.tokenService = tokenService;
            this.userRepository = userRepository;
        }
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            String token = getToken(request);
            if(token != null){
                String tokenSubject = tokenService.getTokenSubject(token);
                UserDetails userEntity = userRepository.findByEmail(tokenSubject);
                Authentication authentication = new UsernamePasswordAuthenticationToken(userEntity, null, userEntity.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
            filterChain.doFilter(request, response);
        }
    
        private String getToken(HttpServletRequest request){
            String token = request.getHeader("Authorization");
            if(token == null){
                return null;
            }
            // 注意这里要保留空格,替换"Bearer "而非"Bearer",避免残留空格
            return token.replace("Bearer ", "");
        }
    
    }
    
  4. 额外检查:Token的Subject匹配问题
    注意到TokenService的createToken方法用user.getUsername()作为Subject,但SecurityFilter里用Subject去查询邮箱。如果你的UserEntity的username不是邮箱,需要改成user.getEmail(),否则会查不到用户导致后续空指针。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 00:34:52