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

Spring Auth:如何将认证失败的HTML页面替换为JSON响应

解决方案:在资源服务中统一自定义JSON异常响应

所有配置操作都需要在资源服务里完成,因为是资源服务负责拦截请求、校验令牌权限,异常响应的定制逻辑自然也在这里实现。下面是具体的配置步骤:

1. 定义统一的异常响应DTO

先创建一个用于封装自定义JSON格式的实体类,方便统一返回结构:

public class CustomErrorResponse {
    private int status;
    private String message;
    private long timestamp;

    public CustomErrorResponse(int status, String message) {
        this.status = status;
        this.message = message;
        this.timestamp = System.currentTimeMillis();
    }

    // 生成getter和setter方法
}

2. 自定义认证入口异常处理器(处理未携带令牌的情况)

这个处理器会替换默认的XML格式<UnauthorizedException>响应,当请求没有携带Authorization头时,返回自定义JSON:

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 设置响应格式为JSON
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        // 序列化自定义响应到输出流
        ObjectMapper mapper = new ObjectMapper();
        CustomErrorResponse errorResponse = new CustomErrorResponse(
                HttpServletResponse.SC_UNAUTHORIZED,
                "未提供有效令牌,请先认证"
        );
        mapper.writeValue(response.getOutputStream(), errorResponse);
    }
}

3. 自定义权限不足异常处理器(可选)

如果需要处理令牌有效但权限不足的情况,可以添加这个处理器:

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);

        ObjectMapper mapper = new ObjectMapper();
        CustomErrorResponse errorResponse = new CustomErrorResponse(
                HttpServletResponse.SC_FORBIDDEN,
                "权限不足,无法访问该资源"
        );
        mapper.writeValue(response.getOutputStream(), errorResponse);
    }
}

4. 全局异常处理器(处理无效令牌导致的500错误)

当携带无效令牌时,默认会抛出InvalidTokenException并返回500 HTML错误页,我们需要捕获这个异常并返回自定义JSON:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(InvalidTokenException.class)
    public ResponseEntity<CustomErrorResponse> handleInvalidTokenException(InvalidTokenException ex) {
        CustomErrorResponse errorResponse = new CustomErrorResponse(
                HttpServletResponse.SC_UNAUTHORIZED,
                "令牌无效或已过期,请重新获取"
        );
        return new ResponseEntity<>(errorResponse, HttpStatus.UNAUTHORIZED);
    }

    // 可选:处理其他全局异常,避免返回HTML错误页
    @ExceptionHandler(Exception.class)
    public ResponseEntity<CustomErrorResponse> handleGenericException(Exception ex) {
        CustomErrorResponse errorResponse = new CustomErrorResponse(
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                "服务器内部错误"
        );
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

5. 配置资源服务的Security策略

在你的@EnableResourceServer配置类中,注入并启用上面的自定义处理器:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling()
                    // 启用自定义未认证处理器
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    // 启用自定义权限不足处理器
                    .accessDeniedHandler(customAccessDeniedHandler)
                .and()
                .authorizeRequests()
                    // 所有请求都需要认证
                    .anyRequest().authenticated();
    }

    // 可选:配置你的资源ID(需和认证服务中配置的一致)
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("your-resource-id");
    }
}

效果验证

  • 当完全不发送Authorization头时:返回401状态码和自定义JSON响应,替换原来的XML格式。
  • 当携带无效/过期令牌时:返回401状态码和自定义JSON响应,替换原来的500 HTML错误页。
  • 当令牌有效但权限不足时:返回403状态码和自定义JSON响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 15:02:49