Spring Boot中通过自定义认证服务器验证JWT及空指针问题排查
问题分析与解决方案
一、当前实现的核心问题
你的整体思路是对的:通过过滤器拦截请求、提取JWT、调用认证服务器完成验证,但代码存在多处错误,不仅会触发空指针,还会导致请求无法正常流转:
- 未处理请求头缺失的情况:如果请求没带
AUTHORIZATION头,token会是null,直接调用trim()会触发空指针 - 未实例化
tokenValidateRequest:代码里直接调用tokenValidateRequest.setToken(token),但这个对象根本没创建,必然抛出空指针 - 未执行过滤器链:
doFilter方法最后没调用chain.doFilter(request, response),拦截后请求不会继续往下走,服务B的API永远无法被访问 - RestTemplate可能未正确注入:如果Spring容器里没有配置
RestTemplate的Bean,@Autowired注入的restTemplate会是null,调用exchange时触发空指针
二、空指针异常的具体诱因
你遇到的RestTemplate空指针,大概率是以下某一种情况:
- RestTemplate未被Spring管理:如果项目里没有通过
@Bean配置RestTemplate实例,@Autowired无法注入有效对象,restTemplate为null - token为空时调用trim():请求未携带
AUTHORIZATION头,req.getHeader("AUTHORIZATION")返回null,执行token.trim()直接抛出空指针(这个异常可能被你误以为是RestTemplate抛出的) - tokenValidateRequest未初始化:代码中直接调用
tokenValidateRequest.setToken(token),但这个对象没有通过new TokenValidateRequest()实例化,调用set方法时触发空指针
三、修正后的代码示例
@Autowired private RestTemplate restTemplate; // 务必在Spring配置类中添加RestTemplate的Bean声明,否则@Autowired会失败 // @Bean // public RestTemplate restTemplate() { // return new RestTemplate(); // } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; // 1. 处理请求头缺失的情况 String token = req.getHeader("AUTHORIZATION"); if (token == null || token.trim().isEmpty()) { res.setStatus(HttpServletResponse.SC_UNAUTHORIZED); res.getWriter().write("Missing authorization token"); return; } token = token.trim(); // 2. 初始化token验证请求对象 TokenValidateRequest tokenValidateRequest = new TokenValidateRequest(); tokenValidateRequest.setToken(token); // 3. 构造请求URI URI myURI; try { myURI = new URI("http://localhost:8092/auth-user/validate"); } catch (URISyntaxException e) { res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); res.getWriter().write("Failed to construct validation URI"); throw new RuntimeException(e); } // 4. 调用认证服务器验证 HttpHeaders headers = new HttpHeaders(); HttpEntity<TokenValidateRequest> requestEntity = new HttpEntity<>(tokenValidateRequest, headers); try { restTemplate.exchange(myURI, HttpMethod.POST, requestEntity, String.class); // 验证通过,继续执行过滤器链,让请求到达目标API chain.doFilter(request, response); } catch (Exception e) { // 验证失败,返回未授权 res.setStatus(HttpServletResponse.SC_UNAUTHORIZED); res.getWriter().write("Invalid or expired token"); } }
额外注意事项
- 建议给
AUTHORIZATION头做格式校验(比如是否以Bearer开头),符合JWT的标准传递格式 - 可以给RestTemplate添加超时配置,避免认证服务器响应慢导致服务B请求阻塞
- 生产环境中建议把认证服务器地址配置到配置文件中,不要硬编码
内容的提问来源于stack exchange,提问作者D.Anush
相关产品推荐
相关产品推荐

