Skip to content

Commit

Permalink
fix: 디바이스 관련 에러처리 로직 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
Ogu1208 committed Oct 29, 2024
1 parent 2d52d91 commit 67e9393
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@



import com.sch.chekirout.common.exception.CustomAuthenticationException;
import com.sch.chekirout.device.Serivce.DeviceService;
import com.sch.chekirout.user.domain.User;
import com.sch.chekirout.user.domain.Repository.UserRepository;
import com.sch.chekirout.user.exception.EmailNotVerifiedException;
import com.sch.chekirout.user.exception.UserNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.transaction.Transactional;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
Expand Down Expand Up @@ -50,7 +52,12 @@ public UserDetails loadUserByUsername(String username) {

// 디바이스 검증 로직 호출
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
deviceService.validateDevice(user, request);
try {
deviceService.validateDevice(user, request);
} catch (CustomAuthenticationException e) {
// AuthenticationException으로 예외를 다시 던져 AuthenticationEntryPoint로 이동
throw new AuthenticationCredentialsNotFoundException(e.getMessage(), e);
}

// 사용자의 권한 설정
List<GrantedAuthority> authorities = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.sch.chekirout.auth.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sch.chekirout.common.exception.CustomAuthenticationException;
import com.sch.chekirout.global.presentation.ErrorResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
Throwable cause = authException.getCause();

if (cause instanceof CustomAuthenticationException) {
CustomAuthenticationException customException = (CustomAuthenticationException) cause;

response.setStatus(HttpStatus.BAD_REQUEST.value());
response.setContentType("application/json;charset=UTF-8");

ErrorResponse errorResponse = new ErrorResponse(
customException.getMessage(),
customException.getErrorCode(),
HttpStatus.BAD_REQUEST.value()
);

response.getWriter().write(new ObjectMapper().writeValueAsString(errorResponse));
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@



import com.sch.chekirout.common.exception.CustomAuthenticationException;
import com.sch.chekirout.device.Serivce.DeviceService;
import com.sch.chekirout.device.domain.UserDevice;
import com.sch.chekirout.device.util.DeviceInfoUtil;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import com.sch.chekirout.auth.exception.CustomAccessDeniedHandler;
import com.sch.chekirout.auth.exception.CustomAuthenticationEntryPoint;
import com.sch.chekirout.auth.jwt.filter.JwtRequestFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
Expand All @@ -23,6 +24,7 @@
public class SecurityConfig {

private final CustomAccessDeniedHandler customAccessDeniedHandler;
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtRequestFilter jwtRequestFilter) throws Exception {
Expand All @@ -49,6 +51,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtRequestFilt

http.exceptionHandling(exceptionHandling ->
exceptionHandling
// .authenticationEntryPoint(customAuthenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler)
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sch.chekirout.common.exception;

import org.springframework.security.core.AuthenticationException;

public class CustomAuthenticationException extends AuthenticationException {
private final ErrorCode errorCode;

public CustomAuthenticationException(String message, ErrorCode errorCode) {
super(message);
this.errorCode = errorCode;
}

public ErrorCode getErrorCode() {
return errorCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ public CustomBadRequestException(String message, Throwable cause, ErrorCode erro
super(message, cause);
this.errorCode = errorCode;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ public CustomUnauthorizedException(String message, Throwable cause, ErrorCode er
super(message, cause);
this.errorCode = errorCode;
}


}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.sch.chekirout.device.Serivce;

import com.sch.chekirout.common.exception.CustomAuthenticationException;
import com.sch.chekirout.common.exception.ErrorCode;
import com.sch.chekirout.device.Repository.UserDeviceRepository;
import com.sch.chekirout.device.domain.UserDevice;
import com.sch.chekirout.device.exception.DeviceNotFoundException;
Expand All @@ -8,6 +10,7 @@
import com.sch.chekirout.user.domain.User;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.stereotype.Service;

import java.util.Optional;
Expand All @@ -30,22 +33,23 @@ public void saveOrUpdateDevice(UserDevice device) {
}



public void validateDevice(User user, HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
String currentDeviceInfo = UserAgentUtil.extractDeviceInfo(userAgent);

if(userAgent != null && userAgent.contains("PostmanRuntime")){
if (userAgent != null && userAgent.contains("PostmanRuntime")) {
currentDeviceInfo = "Postman Device";
}

// 기존 디바이스 정보 조회
UserDevice existingDevice = userDeviceRepository.findByUser(user)
.orElseThrow(() -> new DeviceNotFoundException("Device not found for user: " + user.getUsername()));

// 디바이스 정보 비교
if (!existingDevice.getDeviceInfo().equals(currentDeviceInfo)) {
throw new DeviceNotMatchException();
throw new InternalAuthenticationServiceException(
"다른 기기에서 로그인 시도가 감지되었습니다.",
new CustomAuthenticationException(ErrorCode.DEVICE_NOT_MATCH.getMessage(), ErrorCode.DEVICE_NOT_MATCH)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

Expand Down Expand Up @@ -125,5 +126,34 @@ public ResponseEntity<ErrorResponse> handleEmailAlreadyExists(final EmailAlready
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); // 400 Bad Request
}

@ExceptionHandler(value = {InternalAuthenticationServiceException.class})
public ResponseEntity<ErrorResponse> handleInternalAuthenticationServiceException(InternalAuthenticationServiceException exception) {
Throwable cause = exception.getCause();

// CustomAuthenticationException이 원인인 경우에 한해 400으로 응답
if (cause instanceof CustomAuthenticationException) {
CustomAuthenticationException customException = (CustomAuthenticationException) cause;

ErrorResponse errorResponse = new ErrorResponse(
customException.getMessage(),
customException.getErrorCode(),
customException.getErrorCode().getCode()
);

log.error("CustomAuthenticationException 발생: {}", customException.getMessage());

return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}

// 그 외 InternalAuthenticationServiceException
log.error("예상치 못한 인증 오류: {}", exception.getMessage());

ErrorResponse errorResponse = new ErrorResponse(
INTERNAL_SERVER_ERROR.getMessage(),
INTERNAL_SERVER_ERROR,
HttpStatus.INTERNAL_SERVER_ERROR.value()
);

return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

0 comments on commit 67e9393

Please sign in to comment.