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

JWT Token无效时如何返回自定义响应?Spring Security问题求助

问题描述
  1. 启动应用时出现找不到qualifier为'handlerExceptionResolver'的bean错误
  2. 传入无效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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:47:06