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

