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

求助:如何自定义SpringBoot 2 OAuth2的异常响应格式

Customizing Spring Boot 2 OAuth2 Exception Responses

To standardize your exception responses to the desired format ({"status": "error", "message": "..."}), we’ll handle three key cases: OAuth2 unauthorized errors, invalid/expired token errors, and 404 Not Found errors. Here’s a step-by-step implementation:

1. Create a Custom Error Response DTO

First, define a simple class to represent your uniform error structure:

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class CustomErrorResponse {
    private String status;
    private String message;

    public CustomErrorResponse(String status, String message) {
        this.status = status;
        this.message = message;
    }

    // Getters and setters (or use Lombok's @Data for brevity)
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
}

2. Customize OAuth2 Authentication Entry Point

This handles the unauthorized and invalid_token errors (like expired tokens). Extend Spring’s OAuth2AuthenticationEntryPoint to override the response format:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CustomOAuth2AuthenticationEntryPoint extends OAuth2AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

        // Customize error messages for specific cases
        String errorMessage = authException.getMessage();
        if (errorMessage.contains("Access token expired")) {
            errorMessage = "Access token has expired. Please obtain a new token.";
        } else if (errorMessage.contains("Full authentication is required")) {
            errorMessage = "Full authentication is required to access this resource.";
        }

        CustomErrorResponse errorResponse = new CustomErrorResponse("error", errorMessage);
        new ObjectMapper().writeValue(response.getOutputStream(), errorResponse);
    }
}

3. Register the Custom Entry Point in Resource Server Config

Update your resource server configuration to use the custom entry point:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private CustomOAuth2AuthenticationEntryPoint customOAuth2AuthenticationEntryPoint;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(customOAuth2AuthenticationEntryPoint);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(customOAuth2AuthenticationEntryPoint);
    }
}

4. Handle 404 Not Found Errors

Use a @ControllerAdvice to catch Spring MVC’s NoHandlerFoundException and format it to your desired structure:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<CustomErrorResponse> handleNotFoundError(NoHandlerFoundException ex) {
        CustomErrorResponse errorResponse = new CustomErrorResponse("error", "The requested resource was not found.");
        return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
    }

    // Optional: Handle AccessDeniedException for forbidden requests
    @ExceptionHandler(org.springframework.security.access.AccessDeniedException.class)
    public ResponseEntity<CustomErrorResponse> handleAccessDeniedError(org.springframework.security.access.AccessDeniedException ex) {
        CustomErrorResponse errorResponse = new CustomErrorResponse("error", "You do not have permission to access this resource.");
        return new ResponseEntity<>(errorResponse, HttpStatus.FORBIDDEN);
    }
}

5. Enable 404 Exception Throwing

Add these properties to your application.properties (or application.yml) to make Spring Boot throw NoHandlerFoundException when a path isn’t mapped:

spring.mvc.throw-exception-if-no-handler-found=true
spring.web.resources.add-mappings=false

Testing the Changes

  • When accessing a protected resource without authentication, you’ll get:
    {"status": "error", "message": "Full authentication is required to access this resource."}
    
  • When using an expired token:
    {"status": "error", "message": "Access token has expired. Please obtain a new token."}
    
  • When accessing a non-existent path:
    {"status": "error", "message": "The requested resource was not found."}
    

This setup ensures all your exception responses follow the same custom format, making it easier for client applications to handle errors consistently.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 14:22:37