From 963b255bde13a26b5924be13668f7070abf1d5cb Mon Sep 17 00:00:00 2001 From: yang Date: Tue, 27 Jun 2023 17:54:14 +0900 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20exception=20=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/config/security/jwt/filter/JwtFilter.java | 9 +++++---- .../global/exception/GlobalExceptionHandler.java | 12 ++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java b/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java index c81e3f3..68fc32e 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java @@ -47,18 +47,19 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse log.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); } } catch (SecurityException | MalformedJwtException e) { - log.error("exception", e.getMessage()); + log.error("exception : {}", e.getMessage()); throw new SecurityException.InvalidJwtFormatException(JwtExcpetionMessage.INVALID_FORMAT.getMessage(), JwtExcpetionCode.INVALID_FORMAT.getCode(), HttpStatus.FORBIDDEN); } catch (ExpiredJwtException e) { - log.error("exception", e.getMessage()); + log.error("exception : {}", e.getMessage()); throw new SecurityException.ExpiredJwtException(JwtExcpetionMessage.JWT_EXPIRED.getMessage(), JWT_EXPIRED.getCode(), HttpStatus.FORBIDDEN); } catch (UnsupportedJwtException e) { - log.error("exception", e.getMessage()); + log.error("exception : {}", e.getMessage()); throw new SecurityException.NonSupportedJwtException(JwtExcpetionMessage.JWT_NOT_SUPPORTED.getMessage(), JWT_NOT_SUPPORTED.getCode(), HttpStatus.FORBIDDEN); } catch (IllegalArgumentException e) { - log.error("exception", e.getMessage()); + log.error("exception : {}", e.getMessage()); throw new SecurityException.WrongTokenException(JwtExcpetionMessage.WRONG_TOKEN.getMessage(), WRONG_TOKEN.getCode(), HttpStatus.FORBIDDEN); } catch (Exception e) { + log.error("exception : {}", e.getMessage()); throw new SecurityException.UnKnownException(JwtExcpetionMessage.UNKHOWN_EXCEPTION.getMessage(), UNKHOWN_EXCEPTION.getCode(), HttpStatus.FORBIDDEN); } } diff --git a/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java b/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java index 30f73a3..923c46a 100644 --- a/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java @@ -30,21 +30,21 @@ public class GlobalExceptionHandler { @ExceptionHandler(AuthenticationException.class) public ResponseEntity LoginException(AuthenticationException ex, HttpServletRequest request) { String errorCode = UserFailCode.NOT_FOUND_USER.getCode(); - log.warn(LOG_FORMAT, ex.getClass(), errorCode, ex.getMessage()); + log.error(LOG_FORMAT, ex.getClass(), errorCode, ex.getMessage()); return ResponseEntity.ok(new ErrorResponse(errorCode, UserFailMessage.NOT_FOUND_USER.getMessage())); } @ExceptionHandler(ClassCastException.class) public ResponseEntity AuthorizationException(ClassCastException ex, HttpServletRequest request) { String errorCode = JwtExcpetionCode.WRONG_TOKEN.getCode(); - log.warn(LOG_FORMAT, ex.getClass(), errorCode, JwtExcpetionMessage.WRONG_TOKEN); + log.error(LOG_FORMAT, ex.getClass(), errorCode, JwtExcpetionMessage.WRONG_TOKEN); slackMessage.sendSlackAlertErrorLog(ex, errorCode, request); return ResponseEntity.ok(new ErrorResponse(errorCode, JwtExcpetionMessage.WRONG_TOKEN.getMessage())); } @ExceptionHandler(ApplicationException.class) public ResponseEntity handleApplicationException(ApplicationException ex, HttpServletRequest request) { - log.warn(LOG_FORMAT, ex.getClass().getSimpleName(), ex.getErrorCode(), ex.getMessage()); + log.error(LOG_FORMAT, ex.getClass().getSimpleName(), ex.getErrorCode(), ex.getMessage()); slackMessage.sendSlackAlertErrorLog(ex, ex.getErrorCode(), request); return ResponseEntity.status(ex.getHttpStatus()).body(new ErrorResponse(ex.getErrorCode(), ex.getMessage())); } @@ -52,7 +52,7 @@ public ResponseEntity handleApplicationException(ApplicationExcep @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity methodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) { String errorCode = requireNonNull(ex.getFieldError()).getDefaultMessage(); - log.warn(LOG_FORMAT, ex.getClass().getSimpleName(), errorCode, ex.getMessage()); + log.error(LOG_FORMAT, ex.getClass().getSimpleName(), errorCode, ex.getMessage()); slackMessage.sendSlackAlertErrorLog(ex, errorCode, request); return ResponseEntity.status(HttpStatus.BAD_REQUEST.value()).body(new ErrorResponse(errorCode, ex.getMessage())); } @@ -61,7 +61,7 @@ public ResponseEntity methodArgumentNotValidException(MethodArgum public ResponseEntity handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex, HttpServletRequest request) { String errorCode = "405 METHOD_NOT_ALLOWED"; String message = "클라이언트가 사용한 HTTP 메서드가 리소스에서 허용되지 않습니다."; - log.warn(LOG_FORMAT, ex.getClass().getSimpleName(), errorCode, ex.getMessage()); + log.error(LOG_FORMAT, ex.getClass().getSimpleName(), errorCode, ex.getMessage()); ErrorResponse errorResponse = new ErrorResponse(errorCode, message); slackMessage.sendSlackAlertErrorLog(ex, errorCode, request); return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(errorResponse); @@ -72,7 +72,7 @@ public ResponseEntity handleException(Exception ex, HttpServletRe ex.printStackTrace(); String errorCode = "500 INTERNAL_SERVER_ERROR"; String message = "서버에서 요청을 처리하는 동안 오류가 발생했습니다."; - log.warn(LOG_FORMAT, ex.getClass().getSimpleName(), errorCode, ex.getMessage()); + log.error(LOG_FORMAT, ex.getClass().getSimpleName(), errorCode, ex.getMessage()); ErrorResponse errorResponse = new ErrorResponse(errorCode, message); slackMessage.sendSlackAlertErrorLog(ex, errorCode, request); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); From aa3520de41eda098182416bda7ab091b3aa3d359 Mon Sep 17 00:00:00 2001 From: yang Date: Fri, 30 Jun 2023 01:03:00 +0900 Subject: [PATCH 2/5] =?UTF-8?q?refactor:=20null=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/chilling/encore/domain/Center.java | 9 +++++---- .../chilling/encore/domain/FreeBoard.java | 8 ++++++-- .../encore/domain/FreeBoardComments.java | 8 +++++--- .../encore/domain/LearningCenter.java | 9 +++++---- .../java/chilling/encore/domain/Lecture.java | 20 +++++++++++++------ .../encore/domain/LectureMessage.java | 14 ++++++++----- .../encore/domain/ListenComments.java | 8 +++++--- .../encore/domain/ListenTogether.java | 15 +++++++------- .../chilling/encore/domain/Participants.java | 4 ++-- .../java/chilling/encore/domain/Program.java | 9 ++++++--- .../java/chilling/encore/domain/Review.java | 11 +++++----- .../encore/domain/ReviewComments.java | 8 +++++--- .../chilling/encore/domain/TeacherInfo.java | 2 +- .../java/chilling/encore/domain/User.java | 14 ++++++++++++- .../config/security/SecurityConfig.java | 2 -- .../jwt/filter/CustomAccessDeniedHandler.java | 11 +++++----- .../CustomAuthenticationEntryPoint.java | 13 +++++------- .../exception/GlobalExceptionHandler.java | 2 +- 18 files changed, 100 insertions(+), 67 deletions(-) diff --git a/src/main/java/chilling/encore/domain/Center.java b/src/main/java/chilling/encore/domain/Center.java index 20bd855..ba1eb0b 100644 --- a/src/main/java/chilling/encore/domain/Center.java +++ b/src/main/java/chilling/encore/domain/Center.java @@ -2,10 +2,7 @@ import lombok.*; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import javax.persistence.*; @Entity @AllArgsConstructor @@ -16,9 +13,13 @@ public class Center { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long regionIdx; + @Column(nullable = false) private String url; + @Column(nullable = false) private String region; + @Column(nullable = false) private int favCount; + @Column(nullable = false) private String tell; public void plusFavCount() { diff --git a/src/main/java/chilling/encore/domain/FreeBoard.java b/src/main/java/chilling/encore/domain/FreeBoard.java index 3a89570..d8cf448 100644 --- a/src/main/java/chilling/encore/domain/FreeBoard.java +++ b/src/main/java/chilling/encore/domain/FreeBoard.java @@ -18,14 +18,18 @@ public class FreeBoard { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long freeBoardIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; + @Column(nullable = false) private String title; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String content; + @Column(nullable = false) private String region; + @Column(nullable = false) private int hit; @CreationTimestamp + @Column(nullable = false) private LocalDateTime createdAt; @UpdateTimestamp private LocalDateTime updatedAt; diff --git a/src/main/java/chilling/encore/domain/FreeBoardComments.java b/src/main/java/chilling/encore/domain/FreeBoardComments.java index 908cc40..d4a0e6a 100644 --- a/src/main/java/chilling/encore/domain/FreeBoardComments.java +++ b/src/main/java/chilling/encore/domain/FreeBoardComments.java @@ -20,17 +20,19 @@ public class FreeBoardComments { private Long freeBoardCommentIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "freeBoardIdx") + @JoinColumn(name = "freeBoardIdx", nullable = false) private FreeBoard freeBoard; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String content; + @Column(nullable = false) private boolean isDelete; @CreationTimestamp + @Column(nullable = false) private LocalDateTime createdAt; @JsonBackReference diff --git a/src/main/java/chilling/encore/domain/LearningCenter.java b/src/main/java/chilling/encore/domain/LearningCenter.java index 97f1d21..188ae46 100644 --- a/src/main/java/chilling/encore/domain/LearningCenter.java +++ b/src/main/java/chilling/encore/domain/LearningCenter.java @@ -2,10 +2,7 @@ import lombok.*; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import javax.persistence.*; @Entity @AllArgsConstructor @@ -16,8 +13,12 @@ public class LearningCenter { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long learningCenterIdx; + @Column(nullable = false) private String region; + @Column(nullable = false) private String learningName; + @Column(nullable = false) private double x; + @Column(nullable = false) private double y; } diff --git a/src/main/java/chilling/encore/domain/Lecture.java b/src/main/java/chilling/encore/domain/Lecture.java index 0860638..8da6591 100644 --- a/src/main/java/chilling/encore/domain/Lecture.java +++ b/src/main/java/chilling/encore/domain/Lecture.java @@ -1,6 +1,7 @@ package chilling.encore.domain; import lombok.*; +import org.hibernate.annotations.CreationTimestamp; import javax.persistence.*; import java.time.LocalDate; @@ -16,24 +17,31 @@ public class Lecture { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long lectureIdx; - @ManyToOne - @JoinColumn(name = "teacherInfoIdx") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "teacherInfoIdx", nullable = false) private TeacherInfo teacherInfo; + @Column(nullable = false) private String title; + @Column(nullable = false) private String category; + @Column(nullable = false) private int price; + @Column(nullable = false) private int goalNum; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String lectureObjective; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String lectureContent; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String lectureMethod; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String lectureRequired; @Column(columnDefinition = "TEXT") private String image; + @Column(nullable = false) private String region; + @Column(nullable = false) + @CreationTimestamp private LocalDate createdAt; @OneToMany(mappedBy = "lecture") private List lectureMessages = new ArrayList<>(); diff --git a/src/main/java/chilling/encore/domain/LectureMessage.java b/src/main/java/chilling/encore/domain/LectureMessage.java index 407b554..7c59ca1 100644 --- a/src/main/java/chilling/encore/domain/LectureMessage.java +++ b/src/main/java/chilling/encore/domain/LectureMessage.java @@ -17,18 +17,22 @@ public class LectureMessage { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long lectureMessageIdx; - @ManyToOne - @JoinColumn(name = "lectureIdx") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lectureIdx", nullable = false) private Lecture lecture; - @ManyToOne - @JoinColumn(name = "userIdx") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "userIdx", nullable = false) private User user; - @Column(columnDefinition = "text") + @Column(columnDefinition = "text", nullable = false) private String content; + @Column(nullable = false) private String email; + @Column(nullable = false) private String tel; @ColumnDefault("false") + @Column(nullable = false) private boolean isRead; @CreationTimestamp + @Column(nullable = false) private LocalDate createdAt; } diff --git a/src/main/java/chilling/encore/domain/ListenComments.java b/src/main/java/chilling/encore/domain/ListenComments.java index d5217de..2af4aeb 100644 --- a/src/main/java/chilling/encore/domain/ListenComments.java +++ b/src/main/java/chilling/encore/domain/ListenComments.java @@ -20,17 +20,19 @@ public class ListenComments { private Long listenCommentIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "listenIdx") + @JoinColumn(name = "listenIdx", nullable = false) private ListenTogether listenTogether; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String content; + @Column(nullable = false) private boolean isDelete; @CreationTimestamp + @Column(nullable = false) private LocalDateTime createdAt; @JsonBackReference diff --git a/src/main/java/chilling/encore/domain/ListenTogether.java b/src/main/java/chilling/encore/domain/ListenTogether.java index 06198cf..4492dfe 100644 --- a/src/main/java/chilling/encore/domain/ListenTogether.java +++ b/src/main/java/chilling/encore/domain/ListenTogether.java @@ -21,28 +21,27 @@ public class ListenTogether { private Long listenIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "programIdx") private Program program; - + @Column(nullable = false) private String title; - - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String content; - + @Column(nullable = false) private int hit; - + @Column(nullable = false) private int goalNum; - @CreationTimestamp + @Column(nullable = false) private LocalDateTime createdAt; @UpdateTimestamp private LocalDateTime updatedAt; @OneToMany(mappedBy = "listenTogether") - List listenComments = new ArrayList<>(); + List listexnComments = new ArrayList<>(); @OneToMany(mappedBy = "listenTogether") List participants = new ArrayList<>(); diff --git a/src/main/java/chilling/encore/domain/Participants.java b/src/main/java/chilling/encore/domain/Participants.java index 16c47f7..1edf2c7 100644 --- a/src/main/java/chilling/encore/domain/Participants.java +++ b/src/main/java/chilling/encore/domain/Participants.java @@ -14,9 +14,9 @@ public class Participants { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long participantsIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "listenIdx") + @JoinColumn(name = "listenIdx", nullable = false) private ListenTogether listenTogether; } diff --git a/src/main/java/chilling/encore/domain/Program.java b/src/main/java/chilling/encore/domain/Program.java index 823eb64..55ab53e 100644 --- a/src/main/java/chilling/encore/domain/Program.java +++ b/src/main/java/chilling/encore/domain/Program.java @@ -16,13 +16,16 @@ public class Program { private Long programIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "learningCenterIdx") + @JoinColumn(name = "learningCenterIdx", nullable = false) private LearningCenter learningCenter; - + @Column(nullable = false) private String programName; + @Column(nullable = false) private String category; + @Column(nullable = false) private String url; - + @Column(nullable = false) private LocalDate startDate; + @Column(nullable = false) private LocalDate endDate; } diff --git a/src/main/java/chilling/encore/domain/Review.java b/src/main/java/chilling/encore/domain/Review.java index 10e046b..2fe9c85 100644 --- a/src/main/java/chilling/encore/domain/Review.java +++ b/src/main/java/chilling/encore/domain/Review.java @@ -21,27 +21,28 @@ public class Review { private Long reviewIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "programIdx") + @JoinColumn(name = "programIdx", nullable = false) private Program program; private int week; - + @Column(nullable = false) private String title; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String content; @Column(columnDefinition = "TEXT") private String image; + @Column(nullable = false) private int hit; @CreationTimestamp + @Column(nullable = false) private LocalDateTime createdAt; @UpdateTimestamp private LocalDateTime updatedAt; - @OneToMany(mappedBy = "review") private List reviewComments = new ArrayList<>(); } diff --git a/src/main/java/chilling/encore/domain/ReviewComments.java b/src/main/java/chilling/encore/domain/ReviewComments.java index ea605c9..60cc5d8 100644 --- a/src/main/java/chilling/encore/domain/ReviewComments.java +++ b/src/main/java/chilling/encore/domain/ReviewComments.java @@ -20,16 +20,18 @@ public class ReviewComments { private Long reviewCommentIdx; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "reviewIdx") + @JoinColumn(name = "reviewIdx", nullable = false) private Review review; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String content; + @Column(nullable = false) private boolean isDelete; @CreationTimestamp + @Column(nullable = false) private LocalDateTime createdAt; @JsonBackReference diff --git a/src/main/java/chilling/encore/domain/TeacherInfo.java b/src/main/java/chilling/encore/domain/TeacherInfo.java index 343c4de..c8bbafd 100644 --- a/src/main/java/chilling/encore/domain/TeacherInfo.java +++ b/src/main/java/chilling/encore/domain/TeacherInfo.java @@ -16,7 +16,7 @@ public class TeacherInfo { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long teacherInfoIdx; @OneToOne - @JoinColumn(name = "userIdx") + @JoinColumn(name = "userIdx", nullable = false) private User user; private String introduce; //한줄 소개 @Column(columnDefinition = "TEXT") diff --git a/src/main/java/chilling/encore/domain/User.java b/src/main/java/chilling/encore/domain/User.java index 60fc7a8..7d92476 100644 --- a/src/main/java/chilling/encore/domain/User.java +++ b/src/main/java/chilling/encore/domain/User.java @@ -18,27 +18,39 @@ public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userIdx; - + @Column(nullable = false) private String userId; + @Column(nullable = false) private String name; + @Column(nullable = false) private String gender; + @Column(nullable = false) private int age; + @Column(nullable = false) private String email; + @Column(nullable = false) private String password; + @Column(nullable = false) private String nickName; + @Column(nullable = false) private String phoneNumber; + @Column(nullable = false) private String profile; + @Column(nullable = false) private int status; // 회원 정상 / 휴면 / 탈퇴 상태 @Enumerated(EnumType.STRING) + @Column(nullable = false) private UserConstants.Role role; private String provider; //google, facebook등등 @CreationTimestamp private LocalDate createdAt; private LocalDate loginAt; + @Column(nullable = false) private String region; private String favRegion; + @Column(nullable = false) private int grade; private String favField; diff --git a/src/main/java/chilling/encore/global/config/security/SecurityConfig.java b/src/main/java/chilling/encore/global/config/security/SecurityConfig.java index 95e5bad..e673991 100644 --- a/src/main/java/chilling/encore/global/config/security/SecurityConfig.java +++ b/src/main/java/chilling/encore/global/config/security/SecurityConfig.java @@ -72,8 +72,6 @@ protected void configure(HttpSecurity http) throws Exception { .and() .exceptionHandling() .authenticationEntryPoint(customAuthenticationEntryPoint) - .and() - .exceptionHandling() .accessDeniedHandler(customAccessDeniedHandler) .and() .addFilterBefore(new JwtFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAccessDeniedHandler.java b/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAccessDeniedHandler.java index 6458ab7..c54ea75 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAccessDeniedHandler.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAccessDeniedHandler.java @@ -12,7 +12,6 @@ import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -28,17 +27,17 @@ public class CustomAccessDeniedHandler implements AccessDeniedHandler { private final SlackMessage slackMessage; @Override - public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { log.error("인증에 실패했습니다."); - AuthorityException e = new AuthorityException( + AuthorityException authorityException = new AuthorityException( JwtExcpetionMessage.NON_AUTHORITY.getMessage(), JwtExcpetionCode.NON_AUTHORITY.getCode(), HttpStatus.FORBIDDEN); - slackMessage.sendSlackAlertErrorLog(e, JwtExcpetionCode.NON_AUTHORITY.getCode(), request); - response.setStatus(e.getHttpStatus().value()); + slackMessage.sendSlackAlertErrorLog(authorityException, JwtExcpetionCode.NON_AUTHORITY.getCode(), request); + response.setStatus(authorityException.getHttpStatus().value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setCharacterEncoding("UTF-8"); - String errorResponseJson = objectMapper.writeValueAsString(new ErrorResponse(e.getErrorCode(), e.getMessage())); + String errorResponseJson = objectMapper.writeValueAsString(new ErrorResponse(authorityException.getErrorCode(), authorityException.getMessage())); response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); } } diff --git a/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAuthenticationEntryPoint.java b/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAuthenticationEntryPoint.java index 0f38bec..7ac5781 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAuthenticationEntryPoint.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/filter/CustomAuthenticationEntryPoint.java @@ -1,21 +1,18 @@ package chilling.encore.global.config.security.jwt.filter; import chilling.encore.global.config.security.exception.SecurityException; -import chilling.encore.global.config.security.jwt.JwtConstants; import chilling.encore.global.config.security.jwt.JwtConstants.JwtExcpetionCode; import chilling.encore.global.config.security.jwt.JwtConstants.JwtExcpetionMessage; import chilling.encore.global.config.slack.SlackMessage; import chilling.encore.global.dto.ErrorResponse; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @@ -27,16 +24,16 @@ public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint private final ObjectMapper objectMapper; @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { - SecurityException.WrongTokenException e = new SecurityException.WrongTokenException( + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + SecurityException.WrongTokenException wrongTokenException = new SecurityException.WrongTokenException( JwtExcpetionMessage.WRONG_TOKEN.getMessage(), JwtExcpetionCode.WRONG_TOKEN.getCode(), HttpStatus.FORBIDDEN); - slackMessage.sendSlackAlertErrorLog(e, JwtExcpetionCode.WRONG_TOKEN.getCode(), request); - response.setStatus(e.getHttpStatus().value()); + slackMessage.sendSlackAlertErrorLog(wrongTokenException, JwtExcpetionCode.WRONG_TOKEN.getCode(), request); + response.setStatus(wrongTokenException.getHttpStatus().value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setCharacterEncoding("UTF-8"); - String errorResponseJson = objectMapper.writeValueAsString(new ErrorResponse(e.getErrorCode(), e.getMessage())); + String errorResponseJson = objectMapper.writeValueAsString(new ErrorResponse(wrongTokenException.getErrorCode(), wrongTokenException.getMessage())); response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); } } diff --git a/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java b/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java index 923c46a..abf5cfa 100644 --- a/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/chilling/encore/global/exception/GlobalExceptionHandler.java @@ -31,6 +31,7 @@ public class GlobalExceptionHandler { public ResponseEntity LoginException(AuthenticationException ex, HttpServletRequest request) { String errorCode = UserFailCode.NOT_FOUND_USER.getCode(); log.error(LOG_FORMAT, ex.getClass(), errorCode, ex.getMessage()); + slackMessage.sendSlackAlertErrorLog(ex, errorCode, request); return ResponseEntity.ok(new ErrorResponse(errorCode, UserFailMessage.NOT_FOUND_USER.getMessage())); } @@ -77,5 +78,4 @@ public ResponseEntity handleException(Exception ex, HttpServletRe slackMessage.sendSlackAlertErrorLog(ex, errorCode, request); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } - } From d94c40e66e84e9a8c331e3adbd6adab59b83b959 Mon Sep 17 00:00:00 2001 From: yang Date: Fri, 30 Jun 2023 02:33:38 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20AccessToken=20Redis=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/security/jwt/JwtTokenProvider.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/chilling/encore/global/config/security/jwt/JwtTokenProvider.java b/src/main/java/chilling/encore/global/config/security/jwt/JwtTokenProvider.java index 6eebd86..210df53 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/JwtTokenProvider.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/JwtTokenProvider.java @@ -2,6 +2,7 @@ import chilling.encore.domain.User; import chilling.encore.global.config.redis.RedisRepository; +import chilling.encore.global.config.security.exception.SecurityException.RemovedAccessTokenException; import chilling.encore.repository.springDataJpa.UserRepository; import io.jsonwebtoken.*; import io.jsonwebtoken.io.Decoders; @@ -10,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -24,6 +26,9 @@ import java.util.NoSuchElementException; import java.util.stream.Collectors; +import static chilling.encore.global.config.security.jwt.JwtConstants.JwtExcpetionCode.REMOVE_ACCESS_TOKEN; +import static chilling.encore.global.config.security.jwt.JwtConstants.JwtExcpetionMessage.REMOVED_ACCESS_TOKEN; + @Slf4j @Component @RequiredArgsConstructor @@ -31,6 +36,9 @@ public class JwtTokenProvider implements InitializingBean { private final RedisRepository redisRepository; private static final String AUTHORITIES_KEY = "auth"; private static final String USER_IDX = "userIdx"; + private static final String ACCESS = "Access"; + private static final String REFRESH = "Refresh"; + private static final String GRANT = "Bearer"; @Value("${jwt.secret}") private String secret; @@ -66,7 +74,7 @@ public TokenInfoResponse createToken(Authentication authentication) { updateRefreshToken(userIdx, refreshToken); - return TokenInfoResponse.from("Bearer", accessToken, refreshToken, accessTokenValidityTime); + return TokenInfoResponse.from(GRANT, accessToken, refreshToken, accessTokenValidityTime); } public TokenInfoResponse oauth2CreateToken(Authentication authentication) { @@ -84,14 +92,14 @@ public TokenInfoResponse oauth2CreateToken(Authentication authentication) { updateRefreshToken(userIdx, refreshToken); - return TokenInfoResponse.from("Bearer", accessToken, refreshToken, accessTokenValidityTime); + return TokenInfoResponse.from(GRANT, accessToken, refreshToken, accessTokenValidityTime); } private String createRefreshToken(String authorities, Date current, Long userIdx) { Date refreshTokenValidity = new Date(current.getTime() + this.refreshTokenValidityTime); String refreshToken = Jwts.builder() - .setSubject("Refresh") + .setSubject(REFRESH) .claim(AUTHORITIES_KEY, authorities) .claim(USER_IDX, userIdx) .setIssuedAt(current) @@ -105,7 +113,7 @@ private String createAccessToken(String authorities, Date current, Long userIdx) Date accessTokenValidity = new Date(current.getTime() + this.accessTokenValidityTime); String accessToken = Jwts.builder() - .setSubject("Access") + .setSubject(ACCESS) .claim(AUTHORITIES_KEY, authorities) .claim(USER_IDX, userIdx) .setIssuedAt(current) @@ -113,6 +121,8 @@ private String createAccessToken(String authorities, Date current, Long userIdx) .setExpiration(accessTokenValidity) .compact(); + log.info("accessToken 저장"); + redisRepository.setValues(ACCESS + userIdx.toString(), accessToken, Duration.ofSeconds(accessTokenValidityTime)); return accessToken; } @@ -157,25 +167,23 @@ private Claims parseClaims(String token) { public boolean validateToken(String token) { try { - Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + checkMultiLogin(token); return true; } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { - log.info("잘못된 JWT 서명입니다."); throw e; } catch (ExpiredJwtException e) { - log.info("만료된 JWT 토큰입니다."); throw e; } catch (UnsupportedJwtException e) { - log.info("지원되지 않는 JWT 토큰입니다."); throw e; } catch (IllegalArgumentException e) { - log.info("JWT 토큰이 잘못되었습니다."); throw e; } } + + public boolean validateRefreshToken(String token) { - if (!getSubject(token).equals("Refresh")) + if (!getSubject(token).equals(REFRESH)) throw new IllegalArgumentException("Refresh Token이 아닙니다."); try { Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); @@ -208,6 +216,14 @@ public boolean checkBlackList(String token) { return true; } + private void checkMultiLogin(String token) { + Jws claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); + String userIdx = claims.getBody().get(USER_IDX).toString(); + log.info("checkMultiple Login"); + if (redisRepository.getValues(ACCESS + userIdx).isEmpty()) + throw new RemovedAccessTokenException(REMOVED_ACCESS_TOKEN.getMessage(), REMOVE_ACCESS_TOKEN.getCode(), HttpStatus.FORBIDDEN); + } + public String getSubject(String token) { Claims claims = parseClaims(token); From eb94b6580f79c5a1e53b9622978841054db53c04 Mon Sep 17 00:00:00 2001 From: yang Date: Fri, 30 Jun 2023 02:34:18 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20AccessToken=20Redis=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/config/security/exception/SecurityException.java | 6 ++++++ .../encore/global/config/security/jwt/JwtConstants.java | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/chilling/encore/global/config/security/exception/SecurityException.java b/src/main/java/chilling/encore/global/config/security/exception/SecurityException.java index 5aa4fd5..7ab0046 100644 --- a/src/main/java/chilling/encore/global/config/security/exception/SecurityException.java +++ b/src/main/java/chilling/encore/global/config/security/exception/SecurityException.java @@ -8,6 +8,12 @@ protected SecurityException(String message, String errorCode, HttpStatus httpSta super(message, errorCode, httpStatus); } + public static class RemovedAccessTokenException extends SecurityException { + public RemovedAccessTokenException(String message, String errorCode, HttpStatus httpStatus) { + super(message, errorCode, httpStatus); + } + } + public static class InvalidJwtFormatException extends SecurityException { public InvalidJwtFormatException(String message, String errorCode, HttpStatus httpStatus) { super(message, errorCode, httpStatus); diff --git a/src/main/java/chilling/encore/global/config/security/jwt/JwtConstants.java b/src/main/java/chilling/encore/global/config/security/jwt/JwtConstants.java index 9734280..b6efd0b 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/JwtConstants.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/JwtConstants.java @@ -12,7 +12,8 @@ public enum JwtExcpetionMessage { JWT_NOT_SUPPORTED("[ERROR] 지원되지 않는 토큰 입니다"), WRONG_TOKEN("[ERROR] 잘못된 토큰 입니다"), NON_AUTHORITY("[ERROR] 권한이 없습니다"), - UNKHOWN_EXCEPTION("[ERROR] 알 수 없는 예외 발생!!"); + UNKHOWN_EXCEPTION("[ERROR] 알 수 없는 예외 발생!!"), + REMOVED_ACCESS_TOKEN("[ERROR] 다른 컴퓨터에서 로그인 되었습니다."); private final String message; } @@ -24,7 +25,8 @@ public enum JwtExcpetionCode { JWT_NOT_SUPPORTED("jwt003"), WRONG_TOKEN("jwt004"), UNKHOWN_EXCEPTION("jwt005"), - NON_AUTHORITY("jwt006"); + NON_AUTHORITY("jwt006"), + REMOVE_ACCESS_TOKEN("jwt007"); private final String code; } From 5d29f847225af1f25338bad8dbc9d238130ac2f7 Mon Sep 17 00:00:00 2001 From: yang Date: Fri, 30 Jun 2023 02:34:29 +0900 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20AccessToken=20Redis=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/jwt/filter/JwtExceptionFilter.java | 14 +++++++++----- .../config/security/jwt/filter/JwtFilter.java | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtExceptionFilter.java b/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtExceptionFilter.java index 9126c74..785b3a8 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtExceptionFilter.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtExceptionFilter.java @@ -16,6 +16,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.nio.charset.StandardCharsets; @Component @RequiredArgsConstructor @@ -29,23 +30,26 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse filterChain.doFilter(request, response); } catch (ExpiredJwtException e) { String errorResponseJson = getErrorResponseJson(request, response, e); - response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); + response.getOutputStream().write(errorResponseJson.getBytes(StandardCharsets.UTF_8)); } catch (InvalidJwtFormatException e) { String errorResponseJson = getErrorResponseJson(request, response, e); - response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); + response.getOutputStream().write(errorResponseJson.getBytes(StandardCharsets.UTF_8)); } catch (NonSupportedJwtException e) { String errorResponseJson = getErrorResponseJson(request, response, e); - response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); + response.getOutputStream().write(errorResponseJson.getBytes(StandardCharsets.UTF_8)); } catch (WrongTokenException e) { String errorResponseJson = getErrorResponseJson(request, response, e); - response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); + response.getOutputStream().write(errorResponseJson.getBytes(StandardCharsets.UTF_8)); } catch (UnKnownException e) { String errorResponseJson = getErrorResponseJson(request, response, e); - response.getOutputStream().write(errorResponseJson.getBytes("UTF-8")); + response.getOutputStream().write(errorResponseJson.getBytes(StandardCharsets.UTF_8)); + } catch (RemovedAccessTokenException e) { + String errorResponseJson = getErrorResponseJson(request, response, e); + response.getOutputStream().write(errorResponseJson.getBytes(StandardCharsets.UTF_8)); } } diff --git a/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java b/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java index 68fc32e..9bef826 100644 --- a/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java +++ b/src/main/java/chilling/encore/global/config/security/jwt/filter/JwtFilter.java @@ -46,6 +46,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse SecurityContextHolder.getContext().setAuthentication(authentication); log.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI); } + } catch (SecurityException.RemovedAccessTokenException e) { + log.error("exception : {}", e.getMessage()); + throw e; } catch (SecurityException | MalformedJwtException e) { log.error("exception : {}", e.getMessage()); throw new SecurityException.InvalidJwtFormatException(JwtExcpetionMessage.INVALID_FORMAT.getMessage(), JwtExcpetionCode.INVALID_FORMAT.getCode(), HttpStatus.FORBIDDEN);