feat: custom 401/403 error handling for unauthenticated requests
Replace default Spring Security 403 responses with custom 401 (not logged in) and 403 (insufficient permissions) JSON error responses via exception handling and global exception handler. Also bump API version to 1.4.0 and add Swagger annotations for the GitHub webhook controller.
This commit is contained in:
@@ -10,14 +10,14 @@ import org.springframework.context.annotation.Configuration;
|
||||
info = @Info(
|
||||
title = "Delta Force Guide Server",
|
||||
description = "API for managing Delta Force game firearm builds",
|
||||
version = "1.3.4",
|
||||
version = "1.4.0",
|
||||
contact = @Contact(
|
||||
name = "Zihlu Wang",
|
||||
email = "zihlu.wang@onixbyte.com"
|
||||
),
|
||||
license = @License(
|
||||
name = "MIT",
|
||||
url = "https://git.onixbyte.cn/onixbyte/delta-force-guide-server/-/raw/main/LICENCE"
|
||||
url = "https://onixbyte.dev/onixbyte/delta-force-guide-server/raw/branch/main/LICENCE"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.onixbyte.deltaforceguide.filter.TokenAuthenticationFilter;
|
||||
import com.onixbyte.deltaforceguide.properties.CookieProperties;
|
||||
import com.onixbyte.deltaforceguide.properties.TokenProperties;
|
||||
import com.onixbyte.deltaforceguide.security.provider.UsernamePasswordAuthenticationProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -19,6 +21,8 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
@@ -34,6 +38,8 @@ import org.springframework.web.cors.CorsConfigurationSource;
|
||||
@EnableConfigurationProperties({TokenProperties.class, CookieProperties.class})
|
||||
public class SecurityConfig {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
|
||||
|
||||
/**
|
||||
* Configures the HTTP security filter chain including endpoint authorisation and JWT filter.
|
||||
*
|
||||
@@ -55,6 +61,16 @@ public class SecurityConfig {
|
||||
.authorizeHttpRequests((customiser) -> customiser
|
||||
.anyRequest().permitAll()
|
||||
)
|
||||
.exceptionHandling(customiser -> customiser
|
||||
.authenticationEntryPoint((request, response, authException) -> {
|
||||
log.error("Unauthenticated request: {}", request, authException);
|
||||
throw new BizException(HttpStatus.UNAUTHORIZED, "请先登录");
|
||||
})
|
||||
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
||||
log.error("Denied request: {}", request, accessDeniedException);
|
||||
throw new BizException(HttpStatus.FORBIDDEN, "权限不足");
|
||||
})
|
||||
)
|
||||
.addFilterAfter(tokenAuthenticationFilter, ExceptionTranslationFilter.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.onixbyte.deltaforceguide.controller;
|
||||
import com.onixbyte.deltaforceguide.domain.dto.GitHubIssueRequest;
|
||||
import com.onixbyte.deltaforceguide.service.WebhookService;
|
||||
import com.onixbyte.deltaforceguide.shared.GitHubWebhookHeader;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -12,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "GitHub WebHook")
|
||||
@RestController
|
||||
@RequestMapping("/webhooks/github")
|
||||
public class GitHubWebhookController {
|
||||
@@ -24,6 +27,7 @@ public class GitHubWebhookController {
|
||||
this.webhookService = webhookService;
|
||||
}
|
||||
|
||||
@Operation(description = "GitHub WebHook 接口")
|
||||
@PostMapping
|
||||
public ResponseEntity<Void> handleWebhook(
|
||||
@RequestHeader(GitHubWebhookHeader.EVENT) String event,
|
||||
|
||||
@@ -2,7 +2,11 @@ package com.onixbyte.deltaforceguide.controller;
|
||||
|
||||
import com.onixbyte.deltaforceguide.domain.dto.ErrorResponse;
|
||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@@ -20,5 +24,22 @@ public class GlobalExceptionHandler {
|
||||
return ResponseEntity.status(status)
|
||||
.body(new ErrorResponse(exception.getMessage()));
|
||||
}
|
||||
|
||||
@ExceptionHandler(AuthenticationException.class)
|
||||
public ResponseEntity<ErrorResponse> handleAuthenticationException(AuthenticationException exception) {
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
|
||||
.body(new ErrorResponse("请先登录"));
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException exception) {
|
||||
var authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
var httpStatus = authentication == null || !authentication.isAuthenticated()
|
||||
? HttpStatus.UNAUTHORIZED
|
||||
: HttpStatus.FORBIDDEN;
|
||||
var message = httpStatus == HttpStatus.UNAUTHORIZED ? "请先登录" : "权限不足";
|
||||
return ResponseEntity.status(httpStatus)
|
||||
.body(new ErrorResponse(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user