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

Spring Boot中HttpServletRequest获取X509Certificate返回null求助

解决Spring Boot中HttpServletRequest获取客户端证书返回null的问题

你已经通过Spring Security的X509认证成功提取了证书中的用户名,但无法从HttpServletRequest的javax.servlet.request.X509Certificate属性获取证书,核心原因是Spring Security默认不会将X509认证过程中拿到的证书自动存入请求属性,可以通过以下两种方式解决:

方案1:直接从Authentication对象获取证书

Spring Security完成X509认证后,会生成X509AuthenticationToken,其中直接持有客户端证书。你可以在控制器中注入Authentication对象并强转,直接获取证书:

@Controller
public class CertController {

    @PreAuthorize("hasAuthority('ROLE_USER')")
    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public String verifyCert(Authentication authentication) {
        if (authentication instanceof X509AuthenticationToken x509Token) {
            X509Certificate cert = x509Token.getCertificate();
            if (cert != null) {
                System.out.println("certs is not null");
                return cert.toString();
            }
        }
        return "Error";
    }
}

方案2:自定义过滤器将证书存入请求属性

如果需要保持原有控制器代码不变,可以添加一个自定义过滤器,在认证完成后将证书存入HttpServletRequest的属性中:

修改SecurityFilterChain配置

@SpringBootApplication
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class X509AuthenticationServer {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 添加自定义过滤器,将证书存入request属性
        http.addFilterBefore(new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
                Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                if (auth instanceof X509AuthenticationToken) {
                    X509Certificate cert = ((X509AuthenticationToken) auth).getCertificate();
                    if (cert != null) {
                        request.setAttribute("javax.servlet.request.X509Certificate", new X509Certificate[]{cert});
                    }
                }
                filterChain.doFilter(request, response);
            }
        }, UsernamePasswordAuthenticationFilter.class)
        .authorizeHttpRequests()
        .anyRequest()
        .authenticated()
        .and().x509()
        .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
        .userDetailsService(userDetailsService());
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> {
            System.out.println("Subject: " + username);
            return new User(username, "",
                    AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
        };
    }
}

完成配置后,你原有控制器中通过request.getAttribute("javax.servlet.request.X509Certificate")的代码就能正常获取证书数组。

补充说明

你当前的application.properties配置是正确的,server.ssl.client-auth=need已经强制要求客户端证书,且X509认证能正常提取用户名也证明了证书已被容器接收并交由Spring Security处理,只是没有自动存入请求属性而已。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:38:12