JWT Token无效时如何返回自定义响应?Spring Security问题求助
问题描述
- 启动应用时出现找不到qualifier为'handlerExceptionResolver'的bean错误
- 传入无效JWT Token时,接口返回500内部服务器错误且响应体为空,无法得到预期的自定义响应
解决方案
一、修复handlerExceptionResolver Bean找不到的问题
Spring默认的HandlerExceptionResolver bean名称是defaultHandlerExceptionResolver,而非handlerExceptionResolver,因此构造函数中的@Qualifier参数错误。
修改两个自定义处理器的构造函数:
CustomBearerAuthenticationEntryPoint
// 方式1:直接移除@Qualifier,Spring会自动注入默认实例 public CustomBearerAuthenticationEntryPoint(HandlerExceptionResolver resolver) { this.resolver = resolver; } // 方式2:保留@Qualifier但修正bean名称 public CustomBearerAuthenticationEntryPoint(@Qualifier("defaultHandlerExceptionResolver") HandlerExceptionResolver resolver) { this.resolver = resolver; }
CustomBearerTokenAccesDeniedHandler
public CustomBearerTokenAccesDeniedHandler(HandlerExceptionResolver resolver) { this.resolver = resolver; }
二、修复无效JWT返回500错误的问题
1. 完善全局异常处理器
当前全局异常仅处理InvalidBearerTokenException,但Spring Security在Token校验失败时会抛出AuthenticationException或其子类,需补充对应处理逻辑:
@ExceptionHandler(AuthenticationException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public ErrorMessage handleAuthenticationException(AuthenticationException ex) { return new ErrorMessage("error", "无效的访问令牌,请重新登录"); } @ExceptionHandler(AccessDeniedException.class) @ResponseStatus(HttpStatus.FORBIDDEN) public ErrorMessage handleAccessDeniedException(AccessDeniedException ex) { return new ErrorMessage("error", "无权限访问该资源"); } // 保留原有InvalidBearerTokenException处理 @ExceptionHandler(InvalidBearerTokenException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public ErrorMessage handleInvalidBearerTokenException(InvalidBearerTokenException ex) { return new ErrorMessage("error", "The access token provided is expired, invalid or malformed."); }
2. 确保JWT过滤器正确抛出异常
检查JwtAuthenticationFilter的doFilterInternal方法,确保Token校验失败时抛出AuthenticationException子类:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = extractTokenFromRequest(request); if (token != null) { try { // 校验Token并生成认证信息 Authentication authentication = jwtTokenManager.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } catch (Exception e) { // 抛出认证异常,交由AuthenticationEntryPoint处理 throw new BadCredentialsException("Invalid JWT token", e); } } filterChain.doFilter(request, response); }
3. 移除控制器中的冗余Token校验
Spring Security过滤器会在控制器执行前完成Token校验,控制器无需重复处理:
@GetMapping("/getProjects") public ResponseEntity<ProjectsApiResponse<ProjectsResponse>> getProjects() { // 从SecurityContext直接获取认证用户ID Long userId = ((UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId(); List<Projects> projects = projectsService.getProjectsByUserId(userId); List<ProjectsResponse> projectsResponseList = projects.stream() .map(project -> new ProjectsResponse(project.getId(), project.getName())) .collect(Collectors.toList()); ProjectsApiResponse<ProjectsResponse> response = new ProjectsApiResponse<>("success", projectsResponseList); return new ResponseEntity<>(response, HttpStatus.OK); }
三、验证SecurityConfig配置
确保SecurityFilterChain中正确关联自定义处理器,当前配置已满足要求,重点确认:
authenticationEntryPoint和accessDeniedHandler已注入自定义实例JwtAuthenticationFilter已添加在UsernamePasswordAuthenticationFilter之前
内容的提问来源于stack exchange,提问作者akif.hasdemir
相关产品推荐
相关产品推荐

