refactor: replace BizException with ResponseStatusException
This commit is contained in:
16 files changed
+97
-93
No files matched your search
@@ -3,6 +3,8 @@ package com.onixbyte.deltaforceguide.config;
|
|||||||
import com.auth0.jwt.JWT;
|
import com.auth0.jwt.JWT;
|
||||||
import com.auth0.jwt.JWTVerifier;
|
import com.auth0.jwt.JWTVerifier;
|
||||||
import com.auth0.jwt.algorithms.Algorithm;
|
import com.auth0.jwt.algorithms.Algorithm;
|
||||||
|
import com.onixbyte.deltaforceguide.exeption.ForbiddenException;
|
||||||
|
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
|
||||||
import com.onixbyte.deltaforceguide.filter.TokenAuthenticationFilter;
|
import com.onixbyte.deltaforceguide.filter.TokenAuthenticationFilter;
|
||||||
import com.onixbyte.deltaforceguide.properties.CookieProperties;
|
import com.onixbyte.deltaforceguide.properties.CookieProperties;
|
||||||
import com.onixbyte.deltaforceguide.properties.TokenProperties;
|
import com.onixbyte.deltaforceguide.properties.TokenProperties;
|
||||||
@@ -12,7 +14,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.ProviderManager;
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
@@ -22,7 +23,6 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
|||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
@@ -43,7 +43,7 @@ public class SecurityConfig {
|
|||||||
/**
|
/**
|
||||||
* Configures the HTTP security filter chain including endpoint authorisation and JWT filter.
|
* Configures the HTTP security filter chain including endpoint authorisation and JWT filter.
|
||||||
*
|
*
|
||||||
* @param http the HTTP security builder
|
* @param httpSecurity the HTTP security builder
|
||||||
* @return the configured security filter chain
|
* @return the configured security filter chain
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -64,11 +64,11 @@ public class SecurityConfig {
|
|||||||
.exceptionHandling(customiser -> customiser
|
.exceptionHandling(customiser -> customiser
|
||||||
.authenticationEntryPoint((request, response, authException) -> {
|
.authenticationEntryPoint((request, response, authException) -> {
|
||||||
log.error("Unauthenticated request: {}", request, authException);
|
log.error("Unauthenticated request: {}", request, authException);
|
||||||
throw new BizException(HttpStatus.UNAUTHORIZED, "请先登录");
|
throw new UnauthorisedException("请先登录");
|
||||||
})
|
})
|
||||||
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
||||||
log.error("Denied request: {}", request, accessDeniedException);
|
log.error("Denied request: {}", request, accessDeniedException);
|
||||||
throw new BizException(HttpStatus.FORBIDDEN, "权限不足");
|
throw new ForbiddenException("权限不足");
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.addFilterAfter(tokenAuthenticationFilter, ExceptionTranslationFilter.class)
|
.addFilterAfter(tokenAuthenticationFilter, ExceptionTranslationFilter.class)
|
||||||
@@ -77,6 +77,7 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the BCrypt password encoder for credential hashing.
|
* Provides the BCrypt password encoder for credential hashing.
|
||||||
|
*
|
||||||
* @return the BCrypt password encoder
|
* @return the BCrypt password encoder
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.onixbyte.deltaforceguide.controller;
|
package com.onixbyte.deltaforceguide.controller;
|
||||||
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.ErrorResponse;
|
import com.onixbyte.deltaforceguide.domain.dto.ErrorResponse;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
@@ -9,6 +8,7 @@ import org.springframework.security.core.AuthenticationException;
|
|||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global exception handler that translates exceptions into standard error responses.
|
* Global exception handler that translates exceptions into standard error responses.
|
||||||
@@ -17,12 +17,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|||||||
*/
|
*/
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
@ExceptionHandler(ResponseStatusException.class)
|
||||||
@ExceptionHandler(BizException.class)
|
public ResponseEntity<ErrorResponse> handleResponseStatusException(ResponseStatusException exception) {
|
||||||
public ResponseEntity<ErrorResponse> handleBizException(BizException exception) {
|
var status = exception.getStatusCode();
|
||||||
var status = exception.getStatus();
|
|
||||||
return ResponseEntity.status(status)
|
return ResponseEntity.status(status)
|
||||||
.body(new ErrorResponse(exception.getMessage()));
|
.body(new ErrorResponse(exception.getReason()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(AuthenticationException.class)
|
@ExceptionHandler(AuthenticationException.class)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.exeption;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
public class BadRequestException extends ResponseStatusException {
|
||||||
|
|
||||||
|
public BadRequestException(String reason) {
|
||||||
|
super(HttpStatus.BAD_REQUEST, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package com.onixbyte.deltaforceguide.exeption;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom runtime exception that carries an HTTP status code for API error responses.
|
|
||||||
*
|
|
||||||
* @author zihluwang
|
|
||||||
*/
|
|
||||||
public class BizException extends RuntimeException {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The HTTP status code associated with this business exception.
|
|
||||||
* <p>
|
|
||||||
* This status code indicates the appropriate HTTP response status that should be returned to
|
|
||||||
* clients when this exception occurs. It enables consistent error handling across
|
|
||||||
* REST API endpoints.
|
|
||||||
*/
|
|
||||||
private final HttpStatus status;
|
|
||||||
|
|
||||||
public BizException(String message) {
|
|
||||||
super(message);
|
|
||||||
this.status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BizException(HttpStatus status, String message) {
|
|
||||||
super(message);
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the HTTP status code associated with this business exception.
|
|
||||||
*
|
|
||||||
* @return the HTTP status code that should be used in the error response
|
|
||||||
*/
|
|
||||||
public HttpStatus getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.exeption;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
public class ForbiddenException extends ResponseStatusException {
|
||||||
|
|
||||||
|
public ForbiddenException(String reason) {
|
||||||
|
super(HttpStatus.FORBIDDEN, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.exeption;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
public class InternalServerErrorException extends ResponseStatusException {
|
||||||
|
|
||||||
|
public InternalServerErrorException(String reason) {
|
||||||
|
super(HttpStatus.INTERNAL_SERVER_ERROR, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.exeption;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
public class NotFoundException extends ResponseStatusException {
|
||||||
|
|
||||||
|
public NotFoundException(String reason) {
|
||||||
|
super(HttpStatus.NOT_FOUND, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.exeption;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
public class UnauthorisedException extends ResponseStatusException {
|
||||||
|
|
||||||
|
public UnauthorisedException(String reason) {
|
||||||
|
super(HttpStatus.UNAUTHORIZED, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package com.onixbyte.deltaforceguide.filter;
|
|||||||
|
|
||||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||||
import com.onixbyte.deltaforceguide.client.TokenClient;
|
import com.onixbyte.deltaforceguide.client.TokenClient;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserManager;
|
import com.onixbyte.deltaforceguide.manager.UserManager;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
|
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
|
||||||
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
||||||
@@ -16,11 +16,11 @@ import org.jspecify.annotations.NonNull;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||||
import org.springframework.web.util.WebUtils;
|
import org.springframework.web.util.WebUtils;
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
var userWrapper = userManager.findByUsername(username);
|
var userWrapper = userManager.findByUsername(username);
|
||||||
if (userWrapper.isEmpty()) {
|
if (userWrapper.isEmpty()) {
|
||||||
throw new BizException(HttpStatus.UNAUTHORIZED, "登录已过期,请重新登录");
|
throw new UnauthorisedException("登录已过期,请重新登录");
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = userWrapper.get();
|
var user = userWrapper.get();
|
||||||
@@ -110,8 +110,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
} catch (JWTVerificationException e) {
|
} catch (JWTVerificationException e) {
|
||||||
log.error("JWT verification failed.", e);
|
log.error("JWT verification failed.", e);
|
||||||
handlerExceptionResolver.resolveException(request, response, null,
|
handlerExceptionResolver.resolveException(request, response, null,
|
||||||
new BizException(HttpStatus.UNAUTHORIZED, "登录已过期,请重新登录"));
|
new UnauthorisedException("登录已过期,请重新登录"));
|
||||||
} catch (BizException e) {
|
} catch (ResponseStatusException e) {
|
||||||
handlerExceptionResolver.resolveException(request, response, null, e);
|
handlerExceptionResolver.resolveException(request, response, null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -1,7 +1,8 @@
|
|||||||
package com.onixbyte.deltaforceguide.interceptor;
|
package com.onixbyte.deltaforceguide.interceptor;
|
||||||
|
|
||||||
import com.onixbyte.crypto.util.CryptoUtil;
|
import com.onixbyte.crypto.util.CryptoUtil;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
|
||||||
|
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
|
||||||
import com.onixbyte.deltaforceguide.manager.WebhookManager;
|
import com.onixbyte.deltaforceguide.manager.WebhookManager;
|
||||||
import com.onixbyte.deltaforceguide.shared.GitHubWebhookHeader;
|
import com.onixbyte.deltaforceguide.shared.GitHubWebhookHeader;
|
||||||
import com.onixbyte.deltaforceguide.wrapper.RepeatedlyReadRequestWrapper;
|
import com.onixbyte.deltaforceguide.wrapper.RepeatedlyReadRequestWrapper;
|
||||||
@@ -10,7 +11,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import org.jspecify.annotations.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class GitHubWebhookInterceptor implements HandlerInterceptor {
|
|||||||
@NonNull Object handler
|
@NonNull Object handler
|
||||||
) {
|
) {
|
||||||
if (!(request instanceof RepeatedlyReadRequestWrapper req)) {
|
if (!(request instanceof RepeatedlyReadRequestWrapper req)) {
|
||||||
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR,
|
throw new InternalServerErrorException(
|
||||||
"Request body is not readable");
|
"Request body is not readable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ public class GitHubWebhookInterceptor implements HandlerInterceptor {
|
|||||||
if (signatureHeader == null || signatureHeader.isBlank()) {
|
if (signatureHeader == null || signatureHeader.isBlank()) {
|
||||||
log.warn("Missing {} header from ip={}",
|
log.warn("Missing {} header from ip={}",
|
||||||
GitHubWebhookHeader.SIGNATURE_256, request.getRemoteAddr());
|
GitHubWebhookHeader.SIGNATURE_256, request.getRemoteAddr());
|
||||||
throw new BizException(HttpStatus.UNAUTHORIZED,
|
throw new UnauthorisedException(
|
||||||
"Missing webhook signature header");
|
"Missing webhook signature header");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,13 +70,13 @@ public class GitHubWebhookInterceptor implements HandlerInterceptor {
|
|||||||
computed.getBytes(StandardCharsets.UTF_8),
|
computed.getBytes(StandardCharsets.UTF_8),
|
||||||
signatureHeader.getBytes(StandardCharsets.UTF_8))) {
|
signatureHeader.getBytes(StandardCharsets.UTF_8))) {
|
||||||
log.warn("Invalid webhook signature from ip={}", request.getRemoteAddr());
|
log.warn("Invalid webhook signature from ip={}", request.getRemoteAddr());
|
||||||
throw new BizException(HttpStatus.UNAUTHORIZED, "Invalid webhook signature");
|
throw new UnauthorisedException("Invalid webhook signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||||
log.error("Failed to compute HMAC-SHA256", e);
|
log.error("Failed to compute HMAC-SHA256", e);
|
||||||
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR,
|
throw new InternalServerErrorException(
|
||||||
"Failed to verify webhook signature");
|
"Failed to verify webhook signature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.DailyPasswordResponse;
|
import com.onixbyte.deltaforceguide.domain.dto.DailyPasswordResponse;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
|
||||||
import com.onixbyte.deltaforceguide.shared.JacksonModules;
|
import com.onixbyte.deltaforceguide.shared.JacksonModules;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.client.RestClient;
|
import org.springframework.web.client.RestClient;
|
||||||
@@ -76,7 +75,7 @@ public class DailyPasswordManager {
|
|||||||
.body(DailyPasswordResponse.class);
|
.body(DailyPasswordResponse.class);
|
||||||
|
|
||||||
if (Objects.isNull(response)) {
|
if (Objects.isNull(response)) {
|
||||||
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, "暂无每日密码数据。");
|
throw new InternalServerErrorException("暂无每日密码数据。");
|
||||||
}
|
}
|
||||||
|
|
||||||
redisTemplate.opsForValue().set(key, response, Duration.ofDays(1L));
|
redisTemplate.opsForValue().set(key, response, Duration.ofDays(1L));
|
||||||
|
|||||||
+6
-6
@@ -1,7 +1,8 @@
|
|||||||
package com.onixbyte.deltaforceguide.security.provider;
|
package com.onixbyte.deltaforceguide.security.provider;
|
||||||
|
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.UserCredential;
|
import com.onixbyte.deltaforceguide.domain.entity.UserCredential;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
|
||||||
|
import com.onixbyte.deltaforceguide.exeption.UnauthorisedException;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserManager;
|
import com.onixbyte.deltaforceguide.manager.UserManager;
|
||||||
import com.onixbyte.deltaforceguide.repository.UserCredentialRepository;
|
import com.onixbyte.deltaforceguide.repository.UserCredentialRepository;
|
||||||
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
||||||
@@ -10,7 +11,6 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Example;
|
import org.springframework.data.domain.Example;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@@ -50,14 +50,14 @@ public class UsernamePasswordAuthenticationProvider implements AuthenticationPro
|
|||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
if (!(authentication instanceof UsernamePasswordAuthentication usernamePasswordAuthentication)) {
|
if (!(authentication instanceof UsernamePasswordAuthentication usernamePasswordAuthentication)) {
|
||||||
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, "用户认证失败,请稍后再试。");
|
throw new InternalServerErrorException("用户认证失败,请稍后再试。");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get userContainer from database
|
// get userContainer from database
|
||||||
var userContainer = userManager.findByUsernameOrEmail(usernamePasswordAuthentication.getPrincipal());
|
var userContainer = userManager.findByUsernameOrEmail(usernamePasswordAuthentication.getPrincipal());
|
||||||
if (userContainer.isEmpty()) {
|
if (userContainer.isEmpty()) {
|
||||||
log.error("User {} is trying to authenticate but no userContainer found.", usernamePasswordAuthentication.getPrincipal());
|
log.error("User {} is trying to authenticate but no userContainer found.", usernamePasswordAuthentication.getPrincipal());
|
||||||
throw new BizException(HttpStatus.UNAUTHORIZED, "用户名或密码错误。");
|
throw new UnauthorisedException("用户名或密码错误。");
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = userContainer.get();
|
var user = userContainer.get();
|
||||||
@@ -68,12 +68,12 @@ public class UsernamePasswordAuthenticationProvider implements AuthenticationPro
|
|||||||
|
|
||||||
// get userContainer credentials from database
|
// get userContainer credentials from database
|
||||||
var userCredentials = userCredentialRepository.findOne(Example.of(userCredentialExample))
|
var userCredentials = userCredentialRepository.findOne(Example.of(userCredentialExample))
|
||||||
.orElseThrow(() -> new BizException(HttpStatus.UNAUTHORIZED, "您还没有配置密码,请联系管理员处理。"));
|
.orElseThrow(() -> new UnauthorisedException("您还没有配置密码,请联系管理员处理。"));
|
||||||
|
|
||||||
// validate password
|
// validate password
|
||||||
if (!passwordEncoder.matches(usernamePasswordAuthentication.getCredentials(), userCredentials.getCredential())) {
|
if (!passwordEncoder.matches(usernamePasswordAuthentication.getCredentials(), userCredentials.getCredential())) {
|
||||||
log.error("User {} is trying to authenticate but password is incorrect.", usernamePasswordAuthentication.getPrincipal());
|
log.error("User {} is trying to authenticate but password is incorrect.", usernamePasswordAuthentication.getPrincipal());
|
||||||
throw new BizException(HttpStatus.UNAUTHORIZED, "用户名或密码错误。");
|
throw new UnauthorisedException("用户名或密码错误。");
|
||||||
}
|
}
|
||||||
|
|
||||||
// erase credentials
|
// erase credentials
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package com.onixbyte.deltaforceguide.service;
|
|||||||
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
|
import com.onixbyte.deltaforceguide.domain.dto.LoginRequest;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.User;
|
import com.onixbyte.deltaforceguide.domain.entity.User;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.InternalServerErrorException;
|
||||||
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
import com.onixbyte.deltaforceguide.security.authentication.UsernamePasswordAuthentication;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ public class AuthService {
|
|||||||
*
|
*
|
||||||
* @param request the login credentials containing principle and password
|
* @param request the login credentials containing principle and password
|
||||||
* @return the authenticated {@link User}
|
* @return the authenticated {@link User}
|
||||||
* @throws BizException if authentication fails or the result type is unexpected
|
|
||||||
*/
|
*/
|
||||||
public User login(LoginRequest request) {
|
public User login(LoginRequest request) {
|
||||||
var _authentication = authenticationManager.authenticate(UsernamePasswordAuthentication
|
var _authentication = authenticationManager.authenticate(UsernamePasswordAuthentication
|
||||||
@@ -43,7 +41,7 @@ public class AuthService {
|
|||||||
"Type mismatched, required type is UsernamePasswordAuthentication but got {}.",
|
"Type mismatched, required type is UsernamePasswordAuthentication but got {}.",
|
||||||
_authentication.getClass()
|
_authentication.getClass()
|
||||||
);
|
);
|
||||||
throw new BizException(HttpStatus.INTERNAL_SERVER_ERROR, "登录服务异常,请稍后再试。");
|
throw new InternalServerErrorException("登录服务异常,请稍后再试。");
|
||||||
}
|
}
|
||||||
|
|
||||||
return authentication.getDetails();
|
return authentication.getDetails();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import com.onixbyte.deltaforceguide.domain.dto.FirearmResponse;
|
|||||||
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
||||||
import com.onixbyte.deltaforceguide.enumeration.FirearmType;
|
import com.onixbyte.deltaforceguide.enumeration.FirearmType;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.NotFoundException;
|
||||||
import com.onixbyte.deltaforceguide.repository.FirearmRepository;
|
import com.onixbyte.deltaforceguide.repository.FirearmRepository;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
@@ -84,7 +84,7 @@ public class FirearmService {
|
|||||||
*/
|
*/
|
||||||
public FirearmResponse updateFirearm(Long id, FirearmRequest request) {
|
public FirearmResponse updateFirearm(Long id, FirearmRequest request) {
|
||||||
var firearm = firearmRepository.findById(id)
|
var firearm = firearmRepository.findById(id)
|
||||||
.orElseThrow(() -> new BizException(HttpStatus.NOT_FOUND, "Firearm not found: " + id));
|
.orElseThrow(() -> new NotFoundException("Firearm not found: " + id));
|
||||||
|
|
||||||
firearm.setName(request.name());
|
firearm.setName(request.name());
|
||||||
firearm.setType(request.type());
|
firearm.setType(request.type());
|
||||||
@@ -105,7 +105,7 @@ public class FirearmService {
|
|||||||
*/
|
*/
|
||||||
public void deleteFirearm(Long id) {
|
public void deleteFirearm(Long id) {
|
||||||
Firearm firearm = firearmRepository.findById(id)
|
Firearm firearm = firearmRepository.findById(id)
|
||||||
.orElseThrow(() -> new BizException(HttpStatus.NOT_FOUND, "Firearm not found: " + id));
|
.orElseThrow(() -> new NotFoundException("Firearm not found: " + id));
|
||||||
firearmRepository.delete(firearm);
|
firearmRepository.delete(firearm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
package com.onixbyte.deltaforceguide.service;
|
package com.onixbyte.deltaforceguide.service;
|
||||||
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.BuildSummaryResponse;
|
import com.onixbyte.deltaforceguide.domain.dto.*;
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.ChangePasswordRequest;
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.UpdateProfileRequest;
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.UserProfileResponse;
|
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.User;
|
import com.onixbyte.deltaforceguide.domain.entity.User;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.UserCredential;
|
import com.onixbyte.deltaforceguide.domain.entity.UserCredential;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.UserRole;
|
import com.onixbyte.deltaforceguide.domain.entity.UserRole;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
import com.onixbyte.deltaforceguide.exeption.BadRequestException;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserCredentialManager;
|
import com.onixbyte.deltaforceguide.manager.UserCredentialManager;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserManager;
|
import com.onixbyte.deltaforceguide.manager.UserManager;
|
||||||
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
|
import com.onixbyte.deltaforceguide.manager.UserRoleManager;
|
||||||
@@ -213,12 +209,11 @@ public class UserService {
|
|||||||
*
|
*
|
||||||
* @param user the authenticated user
|
* @param user the authenticated user
|
||||||
* @param request the change password request containing old and new passwords
|
* @param request the change password request containing old and new passwords
|
||||||
* @throws BizException if the old password is incorrect
|
|
||||||
*/
|
*/
|
||||||
public void changePassword(User user, ChangePasswordRequest request) {
|
public void changePassword(User user, ChangePasswordRequest request) {
|
||||||
var credential = userCredentialManager.findByUserIdAndProvider(user.getId(), CredentialProvider.LOCAL);
|
var credential = userCredentialManager.findByUserIdAndProvider(user.getId(), CredentialProvider.LOCAL);
|
||||||
if (credential.isEmpty() || !passwordEncoder.matches(request.oldPassword(), credential.get().getCredential())) {
|
if (credential.isEmpty() || !passwordEncoder.matches(request.oldPassword(), credential.get().getCredential())) {
|
||||||
throw new BizException(HttpStatus.BAD_REQUEST, "旧密码不正确。");
|
throw new BadRequestException("旧密码不正确。");
|
||||||
}
|
}
|
||||||
var encoded = passwordEncoder.encode(request.newPassword());
|
var encoded = passwordEncoder.encode(request.newPassword());
|
||||||
upsertCredential(user.getId(), CredentialProvider.LOCAL, encoded);
|
upsertCredential(user.getId(), CredentialProvider.LOCAL, encoded);
|
||||||
@@ -243,11 +238,10 @@ public class UserService {
|
|||||||
*
|
*
|
||||||
* @param userId the target user ID
|
* @param userId the target user ID
|
||||||
* @param role the role to assign
|
* @param role the role to assign
|
||||||
* @throws BizException if attempting to assign a protected role
|
|
||||||
*/
|
*/
|
||||||
public void assignRole(Long userId, String role) {
|
public void assignRole(Long userId, String role) {
|
||||||
if (!Role.ROLE_ADMIN.equals(role)) {
|
if (!Role.ROLE_ADMIN.equals(role)) {
|
||||||
throw new BizException(HttpStatus.BAD_REQUEST, "只能通过API分配ROLE_ADMIN角色。");
|
throw new BadRequestException("只能通过API分配ROLE_ADMIN角色。");
|
||||||
}
|
}
|
||||||
var user = ensureUserExists(userId);
|
var user = ensureUserExists(userId);
|
||||||
if (userRoleManager.existsByUserIdAndRole(userId, role)) {
|
if (userRoleManager.existsByUserIdAndRole(userId, role)) {
|
||||||
@@ -265,11 +259,10 @@ public class UserService {
|
|||||||
*
|
*
|
||||||
* @param userId the target user ID
|
* @param userId the target user ID
|
||||||
* @param role the role to remove
|
* @param role the role to remove
|
||||||
* @throws BizException if attempting to remove a protected role
|
|
||||||
*/
|
*/
|
||||||
public void removeRole(Long userId, String role) {
|
public void removeRole(Long userId, String role) {
|
||||||
if (!Role.ROLE_ADMIN.equals(role)) {
|
if (!Role.ROLE_ADMIN.equals(role)) {
|
||||||
throw new BizException(HttpStatus.BAD_REQUEST, "只能通过API移除ROLE_ADMIN角色。");
|
throw new BadRequestException("只能通过API移除ROLE_ADMIN角色。");
|
||||||
}
|
}
|
||||||
ensureUserExists(userId);
|
ensureUserExists(userId);
|
||||||
userRoleManager.deleteByUserIdAndRole(userId, role);
|
userRoleManager.deleteByUserIdAndRole(userId, role);
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package com.onixbyte.deltaforceguide.service;
|
package com.onixbyte.deltaforceguide.service;
|
||||||
|
|
||||||
import com.onixbyte.deltaforceguide.domain.dto.*;
|
import com.onixbyte.deltaforceguide.domain.dto.*;
|
||||||
|
import com.onixbyte.deltaforceguide.exeption.BadRequestException;
|
||||||
import com.onixbyte.deltaforceguide.manager.ModificationManager;
|
import com.onixbyte.deltaforceguide.manager.ModificationManager;
|
||||||
import com.onixbyte.deltaforceguide.manager.WebhookManager;
|
import com.onixbyte.deltaforceguide.manager.WebhookManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.onixbyte.deltaforceguide.exeption.BizException;
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -111,7 +110,7 @@ public class WebhookService {
|
|||||||
toLong(data.get("firearmId")),
|
toLong(data.get("firearmId")),
|
||||||
(String) data.get("firearmName"));
|
(String) data.get("firearmName"));
|
||||||
if (firearmId == null) {
|
if (firearmId == null) {
|
||||||
throw new BizException(HttpStatus.BAD_REQUEST,
|
throw new BadRequestException(
|
||||||
"YAML must contain firearmId or firearmName");
|
"YAML must contain firearmId or firearmName");
|
||||||
}
|
}
|
||||||
String name = (String) data.get("name");
|
String name = (String) data.get("name");
|
||||||
|
|||||||
Reference in new issue
Block a user