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

Spring Security:SecurityContextHolder无法保存认证及JWT生成异常

问题与解决方案:Spring Security JWT生成与默认登录端点问题

问题描述

  • 自定义的JwtGeneratorFilter中,通过SecurityContextHolder.getContext().getAuthentication()获取的Authentication始终为null,导致无法生成JWT;查看BasicAuthenticationFilter时,发现其转换请求值为Authentication也返回null,无法定位错误原因。
  • 自定义/login端点的原因:请求Spring Security默认登录端点时未收到401错误。

疑问

  1. 如何在BasicAuthenticationFilter中使用请求数据并存入SecurityContextHolder?
  2. 如何正确请求Spring Security默认登录端点?

相关代码

JwtGeneratorFilter代码

public class JwtGeneratorFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            SecretKey secretKey = Keys.hmacShaKeyFor(SecurityConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
            String jwt = Jwts.builder().setIssuer("Demo App").setSubject("Jwt token").claim("userName", authentication.getName()).setIssuedAt(new Date()).setExpiration(new Date((new Date().getTime() + 30000000))).signWith(secretKey).compact();
            response.setHeader(SecurityConstants.JWT_HEADER, jwt);
        }
        filterChain.doFilter(request, response);
    }
}

SecurityConfig配置代码

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {

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

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        config.setAllowedOrigins(Collections.singletonList("http://localhost:4200"));
        config.setAllowedMethods(Collections.singletonList("*"));
        config.setAllowCredentials(true);
        config.setAllowedHeaders(Collections.singletonList("*"));
        config.setExposedHeaders(Arrays.asList("Authorization"));
        config.setMaxAge(3600L);
        source.registerCorsConfiguration("/**", config);
        return source;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
        http.csrf(csrf -> csrf.disable()).sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).authorizeHttpRequests(req -> req.requestMatchers("/auth/**").permitAll().anyRequest().authenticated());
        http.formLogin(Customizer.withDefaults())
                .httpBasic(Customizer.withDefaults());

        http.addFilterAfter(new JwtGeneratorFilter(), BasicAuthenticationFilter.class);
        return http.build();
    }

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

}

自定义/login接口代码

@PostMapping("/login")
public String login(@RequestBody User user) {
    Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword()));
    return user.toString();
}

注:authenticate返回的Authentication对象中authenticated为true,但仍无法生成JWT。

解决方案

  • BasicAuthenticationFilter的逻辑是从请求头中获取认证信息,而手动调用authenticationManager.authenticate()完成的认证不会触发过滤器流程,因此SecurityContextHolder中不会存入认证信息,导致JwtGeneratorFilter拿不到Authentication。
  • 初学者可直接沿用默认认证逻辑:将登录信息按Basic Auth格式放在请求头中,此时BasicAuthenticationFilter会自动处理认证,并将Authentication存入SecurityContextHolder,后续JwtGeneratorFilter就能正常生成JWT。
  • 若需自定义登录流程,可按以下步骤实现:
    1. 在自定义/login接口中,通过AuthenticationManager完成用户认证。
    2. 认证通过后,手动将Authentication对象存入SecurityContextHolder.getContext().setAuthentication(authentication)。
    3. 直接在接口中生成JWT并返回给前端(无需依赖JwtGeneratorFilter,或确保过滤器能捕获到此时SecurityContext中的信息)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 07:42:53