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
相关产品推荐
相关产品推荐

